- 0. Introduction
- 1. Configuring the device
- 2. APIs
- 2.1 Python API
- 2.2 Python API (type-checked)
- 2.3 Javascript API
The NIM Sensor Sync device was designed to enable easy real-time synchronization of sensor data and lab experiment (online) software. This is necessary since sensor data capturing devices or software and the experiment software can run on different systems and produce separate data streams. An online experiment might produce a .CSV file or log file on the web server - whereas the sensor capturing software might run on a proband-facing laptop in the lab, producing a different CSV file. Synchronizing these two data streams: from the experiment software and from the sensor data capturing software is essential for correlation of sensor data to events during a lab experiment.
The NIM Sensor Sync provides electrical sensor interfaces that can be controlled over the network via HTTP. Sensor capturing devices such as a biosignalsplux sensor hub can capture the state of these networked sensor outputs that in turn are controlled by the experiment software via an easy HTTP API.
Using the networked sensor outputs, the experiment software can send synchronization pulses to the sensor capturing device. That way, it can place marks in the sensor data - e.g. when a proband started interacting with the experiment software, pressed a certain button, started watching a video, etc.
One NIM Sensor Sync device provides 8 networked sensor outputs. The following illustration shows an exemplary setup, where two lab seats are equipped with a laptop and two different sensors each. All sensors are connected to a 6-channel sensor hub. For synchronization, two inputs of the sensor hub - one for each proband laptop - are connected to the NIM Sensor Sync's sensor outputs. The Sensor Sync device is connected to the Ethernet network, as are all proband laptops and the master PC for the experiment administrator. In this scenario, sensor data synchronization "mark" requests can be sent either by the web server running the experiment backend on the master PC or by the web browsers of the proband laptops during the experiment.
Use the configuration tool after cloning this repository. You can run it by opening it (sample.html) in a browser, no HTTP server required.
This tool allows you to:
- configure a connected device's IP address
- configure a connected device's MAC address
- reboot a connected device -> IP and MAC changes take effect
- read current config (including sensor states)
- change sensor states (outputs)
The default configuration:
- IP:
192.168.2.49
- MAC:
CA.FE.EE.CA.FE.ED
These defaults are restored when you:
- power up the device
- within 5 seconds,
- hold the button for 3 seconds
- (as an indicator that the default config was restored, the LED light will deactivate)
- reboot (power cycle) the device
See python/
The API supports pipenv. Install pipenv by running:
pip install --user pipenv
To install dependencies, run:
$ pipenv install
Then, to run ssync.py
, which tests all API functions against a device using the default
configuration, run the following:
$ pipenv run python ssync.py
Please note that instead of prefixing every command with pipenv run
, you can alternatively also open a pipenv shell:
$ pipenv shell
Ensure you are running python 3.8 or above. Then run:
$ pip install requests
Then, to run ssync.py
, which tests all API functions against a device using the default
configuration, run the following:
$ python ssync.py
# import and init
import SensorSync from ssync
s = SensorSync('192.168.2.49')
# or
# s = SensorSync()
# s.ip = '192.168.2.49'
# set and reset sensors
# valid sensor numbers: 1..8
OK, _ = s.activate(1)
OK, _ = s.reset(1)
# optionally, check the returned html when activating/resetting:
OK, _ = s.activate(1, verify=True)
OK, _ = s.reset(1, verify=True)
# request status
OK, status_html = s.status()
# status_html looks like this:
<html>
Version 2.3
IP=192.168.2.49
MAC=DE.AD.BE.EF.FE.ED
SENSORS=0
</html>
# re-configure device:
OK, _ = s.write_ip('192.168.2.49')
OK, _ = s.write_mac('CA.FE.EE.CA.FE.ED')
OK, _ = s.reboot()
Optionally, a type-checked version of the API exists. It lives in ./python/type_checked_python_3.9_and_above.
The type-checked API requires python 3.9 or above!
Its dependencies are:
python3.9
or aboverequests
: runtime onlymypy
: type-checker, development time onlytypes-requests
: development time only
So, if you just want to use the API, you only need to pip install requests
and you are done.
If you plan to develop and use mypy
for type-checking, we recommend using pipenv. Install
pipenv by running:
pip install --user pipenv
To install dependencies, run:
$ pipenv install -d
Then, to run ssync.py
, which tests all API functions against a device using the default
configuration, run the following:
$ pipenv run python ssync.py
To perform a type-check, run:
$ pipenv run mypy .
Please note that instead of prefixing every command with pipenv run
, you can alternatively also open a pipenv shell:
$ pipenv shell
# import and init
import SensorSync from ssync
s = SensorSync('192.168.2.49')
# or
# s = SensorSync()
# s.ip = '192.168.2.49'
# set and reset sensors
# valid sensor numbers: 1..8
OK, _ = s.activate(1)
OK, _ = s.reset(1)
# optionally, check the returned html when activating/resetting:
OK, _ = s.activate(1, verify=True)
OK, _ = s.reset(1, verify=True)
# request status
OK, status_html = s.status()
# status_html looks like this:
<html>
Version 2.3
IP=192.168.2.49
MAC=DE.AD.BE.EF.FE.ED
SENSORS=0
</html>
# re-configure device:
OK, _ = s.write_ip('192.168.2.49')
OK, _ = s.write_mac('CA.FE.EE.CA.FE.ED')
OK, _ = s.reboot()
See javascript/. A simple demo web page, ssync-demo.html, is provided, too. You can open it directly in the browser, no web server required.
Should your system insist on a web server, there's always:
python3 -m http.server .
// set IP address to use:
// ------------------------------------------------------------------------
set_ssync_ip(ip_address_as_string);
// activate a sensor:
// ------------------------------------------------------------------------
activate_sensor(sensor_number); // sensor number range: 1..8
// de-activate a sensor:
// ------------------------------------------------------------------------
reset_sensor(sensor_number); // sensor number range: 1..8
// read config:
// ------------------------------------------------------------------------
read_config() // returns a promise, access with .then(...)
read_config().then(data => console.log(data.ip, data.mac, data.sensors))
// return values and error handling
// ------------------------------------------------------------------------
// just activate
activate_sensor(1);
// activate sensor and log result to console
activate_sensor(1).then(result_html => console.log(result_html));
// activate sensor and log result to console, catch and log error
activate_sensor(1)
.then(result_html => console.log(result_html))
.catch(function (err) {
console.log('Fetch Error :-S', err);
});
// NOTE: if you chain multiple calls and want them to be executed in order,
// use the `await` keyword. This only works inside of functions:
async function foo() {
console.log('the following happens in order')
// just activate
await activate_sensor(1);
// activate sensor and log result to console
await activate_sensor(1).then(result_html => console.log(result_html));
// activate sensor and log result to console, catch and log error
await activate_sensor(1)
.then(result_html => console.log(result_html))
.catch(function (err) {
console.log('Fetch Error :-S', err);
});
await read_config().then(data => console.log('\n',
'ip: ' + data.ip, '\n',
'mac: ' + data.mac, '\n',
'sensor states: ', data.sensors, '\n',
data)
);
console.log('finished');
}
// call the function
foo();
// see `ssync-demo.html` for an example for how to use this inside of an HTML file.