The device.

Arda.device() describes the machine; Arda.on() tells you when something moved; Arda.system and Arda.wifi act on the machine for an app that owns it.

Working — describes ArdaPlayer v1.2.3

Arda.device()

app/app.js
Arda.device().then(function (d) {
  console.log(d.phase, d.hostname, d.version, d.ips.join(', '));
  if (d.can && d.can.touch && !d.can.keyboard) showBigButtons();
  else showTypedForm();
});
FieldMeaning
phaselocal (developer mode, nothing connected), unregistered, initialising or ready — whether the device is set up, not whether it is online.
networkwhether there is a usable network right now
connected, sincefrom v1.2.0: whether the control connection to ArdaForm is up right now, and since when (ms) it has been up or down (0: never since the player started). The network can be up with the connection down; 'device' fires when this changes
appfrom v1.2.0: {version}, the deployed app's version as ArdaForm named it on the push — for an About screen. Empty on a desk
deviceIdassigned when the device is registered; "" before
pendingCodethe activation code on offer, "" when none
locked, lockReasonwhether an operator has locked the device
versionthe player's version
hostname, model, ipsthe machine's name, its board, and one "interface address" string per interface
wifi{present, connected, ssid}; absent when the machine has no Wi-Fi
hwTail, bleName, bleOnthe last 4 hex digits of the hardware id, the Bluetooth setup name (arda-xxxx), whether it is advertising
screens, inputsthe display connectors and input devices the kernel sees (Linux)
canwhat a person can do at this machine (below)
featureswhat this player build can do on this machine (below)
platformfrom v1.4.0: what the app is running on — {os, mode, kiosk, android}. os is 'android', 'linux', 'windows' or 'macos'; mode how the player was started ('kiosk', 'headless', 'dev'); kiosk is true when the screen is the player's and nobody can leave it — a device on Linux, or an Android tablet once the portal's Kiosk mode holds it (a developer's window and an ordinary Android install say false); android is {deviceOwner, lockTask, home, exitAllowed, sdk, release} and absent elsewhere. One app can lay itself out for a tablet and for a till from this.

It also carries the player's own progress fields (datasets, data, sync, boot, resync, recovery) for its boot screen; use Arda.db.status() instead.

.can — lay out for the machine

FieldTrue when
screena display is connected (false means headless)
keyboarda keyboard with letter keys is attached
mousea mouse or touchpad
toucha touchscreen
audioOut, audioInit can play sound; it can record. Separate questions: a Pi on HDMI has output and no microphone.
  • Each call reports what is attached now; a keyboard plugged into a running till shows on the next call.
  • keyboard means letter keys. A Raspberry Pi's HDMI port, power buttons and IR receivers report key events too, and do not count.
  • On an older player can is absent: treat undefined as "I do not know", never as "no".
  • On your desk, "can" in arda.dev.json sets what the app is told. Write against pointer events, which work for touch and mouse alike.

.features — what this build can do

app/app.js
Arda.device().then(function (d) {
  var f = d.features || [];
  var canPrintJobs  = f.indexOf('printStatus') >= 0;   // print(id, bytes, {copies}, onStatus)
  var cameraMonitor = f.indexOf('cameraScreen') >= 0;  // Arda.camera.show on a second monitor
  var onvif         = f.indexOf('cameraOnvif') >= 0;   // Arda.camera.onvif / discover
});

A name is listed only when this build can do it end to end on this machine. Those an app may care about: camera (motion-JPEG camera path), cameraVideo (the camera's own H.264 in a <video>), cameraScreen, cameraOnvif, printStatus, deviceOptions (from v1.2.1: a select may offer the device's own printers or screens), and from v1.3.0 battery (below), netPrinters (printers on the network) and, on an Android device owner, kiosk — on Android shutdown is missing when the portal forbids closing the player. A missing name means an older player or a machine without it: degrade, do not fail.

Arda.on(kind, fn)

kindfn receivesWhen
'sync'the dataset's namea dataset finished refreshing: read it again
'ack'{highWater, acked, refused, pending}from v1.2.0: ArdaForm answered a batch of your pushes — acked lists the seqs now stored, refused those it will never hold, pending what is still queued per dataset (Data)
'files'{done, total, fetched, fetchedBytes, totalBytes, failed, complete, landed}file sync progress (Files)
'config'the new Arda.configa setting for this device changed
'device'nothingphase, lock or registration changed: call Arda.device(). From v1.2.0 it also fires when the control connection goes up or down: read Arda.db.status().connected. Up to v1.1.17 poll Arda.device().network if you show one
'screens'the display connectors as they now area monitor unplugged, plugged in or swapped (Screens)
'power'{action, error}the power button was pressed and the device is shutting down
'barcode', 'nfc'{kind, text, device, node}a scan or a card read (below)
'battery'the battery, as Arda.battery.status() answersfrom v1.3.0: its level or its state changed (below)
'back'nothingfrom v1.3.0, Android only: the back key was pressed (Android)
'update', 'updateStart'the updatean update is staged; one is about to be applied (Updates)

Register as many listeners as you like. There is no off(): register once, at start-up, and decide inside the listener.

A lock takes the screen. When an operator locks the device, the page is replaced by the player's lock screen, which says why; the app comes back when it is unlocked.

The battery — Arda.battery

Working — from ArdaPlayer v1.3.0, on Android and on Linux machines that have one
app/app.js
function show(b) {
  if (!b.present) return;                        // a box on mains: no battery to show
  drawBattery(b.level, b.state === 'charging', b.timeToEmptySec);
}
Arda.battery.status().then(show);
Arda.on('battery', show);                     // the level or the state moved
fieldvalue
presentfalse on a machine with no battery — everything else is then empty
level0–100
statecharging, discharging, full, not-charging or unknown
pluggedac, usb, wireless or none
timeToEmptySec, timeToFullSecseconds, or null when the machine does not say — on Android the time to empty is an estimate from the current draw
temperatureC, healthas the battery reports them, or null

Feature-test with battery in features; Arda.device()'s can.battery says whether this machine has one. The portal shows the charge on the device page and raises a battery low alert below 15 % while it is not charging, cleared at 20 % or on charge.

Power off, reboot, the power button

app/app.js
document.getElementById('close-shop').onclick = function () {
  saveEverything().then(function () { return Arda.system.shutdown(); });  // or Arda.system.reboot()
};

Arda.on('power', function (p) {
  if (p.error) return;          // the machine refused; the player shows why, the app keeps running
  saveEverything();             // you have about a second
});
  • shutdown() and reboot() resolve {ok: true} and then the machine goes: nothing after the call should be relied on to run. The portal shows the device leaving on purpose.
  • A short press of the power button belongs to the player: it shows "Shutting down" over the page, tells ArdaForm, and powers off. One press is one shutdown. A long press (about five seconds) is the operating system's hard way out.
  • On Android there is no power-off for an app: shutdown() closes the player, and is refused with the reason when the portal forbids it; reboot() works only when the player is the box's device owner (Android).
  • In developer mode your computer is never touched: a five-second notice says what would have happened and the promise resolves {ok: true, simulated: true, message}. Your laptop's power button stays your laptop's.

Wi-Fi

app/app.js
Arda.wifi.list().then(function (nets) {
  // [{ssid: 'shop', signal: 92, security: 'WPA2', band: '', active: true, known: true}, …] strongest first
  drawNetworks(nets);
});

function join(ssid, password) {
  return Arda.wifi.connect(ssid, password).then(
    function (r) { say('Connected to ' + r.ssid); },
    function (e) { say(e.message); }   // e.g. 'wifi: the password for "shop" was not accepted'
  );
}
  • The password is tested first: a wrong one leaves the device on the network it had. An app can offer a Wi-Fi screen without being able to strand the machine.
  • Joining takes the radio down for some seconds even when it works. The connection to ArdaForm blinks; allow the call up to a minute.
  • There is no "forget": that is an operator's decision in the portal's Peripherals tab.
  • From v1.2.3 a device with Wi-Fi and no network lists the networks on its own activation screen and takes the password there. Once your app is running, offering a Wi-Fi screen is the app's job, with these calls.
  • On your desk, "devices": {"wifi": …} in arda.dev.json gives you a pretend radio.

On an Android tablet from ArdaPlayer v1.5.2

A tablet set up as device owner (kiosk mode) manages its Wi-Fi through the same calls: list(), connect(ssid, key) and the new forget(ssid), status() → {present, connected, ssid, signal, routed, managed} and settings(). managed says whether list, connect and forget can work here. An ordinary install cannot add a network since Android 10, so there managed is false and settings() puts Android’s own Wi-Fi panel over the app (elsewhere it rejects). Two differences from a Linux device: the password is not tested first — a wrong one is found out by the join itself, which can take up to thirty seconds, after which the network is dropped again and the tablet goes back to what it had; and a passphrase must be 8 to 63 characters. A network the tablet already remembers is updated in place.

Barcode scanners and card readers

app/app.js
Arda.on('barcode', function (s) {
  // s = {kind: 'barcode', text: '5012345678900', device: 'Symbol Bar Code Scanner', node: 'event7'}
  lookUp(s.text);
});
Arda.on('nfc', function (s) { signIn(s.text); });
  • Scanners and most card readers type their payload and press Enter. The player reads them from the kernel, so each scan carries the device it came from and two scanners never mix.
  • 'nfc' fires for readers recognised as card readers (by USB vendor, or a name containing rfid, nfc or mifare); everything else is 'barcode'.
  • The reader also types into whatever field has focus: the player does not take the keyboard away from the page. Keep no text field focused on a scanning screen, or ignore that typing.

console.* — where your logging goes

  • console.log/info/warn/error/debug works as in any browser and is also copied into the device's own log, marked as coming from the app. Objects are written as JSON.
  • Nothing leaves the device unless log capture is switched on in the portal (the device's Alerts & log tab). The switch expires by itself.
  • The last few hundred lines are always kept on the device, so switching capture on ships what already happened. Log the moment something interesting happens.
  • About 50 lines a second (short bursts higher); the excess is dropped and counted in the log. Log events, not frames.

Checked: the field list, features and can were read from a running player (local run); event names and payloads are from ArdaJS() in the player's internal/devserve/bridge.go. Wi-Fi joining, the power button and the readers were not verified against a device here.