This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Documentation

From Maker to Maker

The 2log documentation is being created here little by little. The documentation was written with the goal to enable Fablabs and Makerspaces to use and operate the 2log system on their own.

All hardware components were intentionally designed based on through-hole parts to allow less experienced makers to solder the parts together.

Feedback welcome!

If any points are not described in enough detail I am grateful for any feedback. Pull requests are welcome.

1 - Overview

What is 2log?

2log is a free community management system for workshops, fablabs, maker- and hackerspaces.

It is a modular hardware and software solution that digitally links machines, users and processes and makes them remotely trackable. Each device with a power cable - from the laser cutter to the coffee machine - can be connected to your 2log instance with the 2log Switch within a few minutes.

Your advantages:

  • Protect the machines from unauthorized use thanks to individual usage authorizations.
  • Bill machine run time either as a flat rate or by the second based on time of use.
  • Transfer your existing machinery to 2log. No changes to the machines are necessary - the manufacturer‘s warranty for the equipment is retained.
  • Reduce your power consumption. Unused machines switch off automatically.
  • Receive statistics on the use of your machines. With 2log you can monitor the load in real time. You can see at any time who has been working on which machine when and where.
  • Use the 2log admin app or the web platform to always have a full overview of the processes in your workshop.
  • Integrate 2log into your existing systems (e.g. CoBot).
  • Bill products like coffee or snacks with a self service terminal.
  • Easy authentication via RFID cards or with with the 2log App by scanning QR Codes.

How it works

In order to integrate a machine into 2log, no structural changes need to be made. The 2log switch is simply plugged between the power plug of the machine and the socket. The setup process is so simple that you can easily do it yourself in minutes.

image

Where should I go next?

2 - Showcases

You want to see that it really works?

No problem - there are a number of workshops from very different sectors that have been using 2log successfully for several years.

2.1 - Shared joinery workshop in Kleve

A commercial joinery that uses 2log to share the use of its machinery between several independent self-employed carpenters and subcontractors.

A carpentry workshop in Kleve that built 2log entirely on its own just by using this online documentation. They experimented extensively and found new ways to integrate even very large machines into 2log. In many cases, access control was implemented by interrupting existing safety mechanisms with relays. For example, by interrupting the circuit of sensors that check whether safety flaps are closed.

The operators of this workshop are also part of the community and are present on the Discord channel. They can provide many tips when it comes to integrating large machines.

A few pictures

2.2 - StudioLab - TU Kaiserslautern

The Studiolab is a workshop for architecture students at the RPTU in Kaiserslautern.

The Machines

In total, we operate:

  • 2x band saws
  • 3x circular saws
  • 2x belt sanders
  • 2x styrocuts
  • 2x disc sanders

How we use 2log.io

Overall, more than 200 students have an active account and use the workshop on a regular basis. Because of the logfiles from every machine, we can keep track of the utilization and wear. This helps us to estimate the condition for example of the saw blades.

Extended opening hours

Students can access the workshop 24/7 via 2log to make models for their assignments during their studies. Due to the traceable history of the machines, we have less vandalism in our workshop. Furthermore, the machines are handled more carefully, and the shop floor is left behind cleaner. We don’t need to employ a supervisor with opening hours, because all the access control and authorization of the machines is handled by 2log. With 2log, its possible to work on the weekends or use the machines whenever it suits you. Before implement this login system, the workshop was crowded and the students had to share the machines. With the 24/7 opening times, the working hours are spread over the entire time. This ensures that the workshop is not overcrowded.

Safety instructions

In addition, we automatically check for a valid safety instruction with 2log. Only after a successful safety training and the safety briefing the account will be added to 2log. This is really important for our insurance protection. The option to create the account for a limited time only helps us to keep track of this topic and ensures that no account has an expired instruction.

Less dust - better air!

Another key advantage with 2log is the fact that we can check and control the dust extraction of the working machines. If extraction is necessary, the machine will only be unlocked if the corresponding extraction is running. As soon as you try to unlock a machine, the extraction starts automatically via 2log and ends afterwards. Therefor you don’t have to worry about turning on or off the ventilation. Because of this, the whole workshop is less dusty which is also healthier for the people working there.

2log - Easy to set up, easy to maintain

Fortunately, the components for the new dots were soldered and assembled for us by the university’s electronics workshop using the instructions on the 2log website. Thanks to the new software version, we were able to use the existing ShellyOS Shelly Plus Plug S to integrate the switches, which meant that the integration did not require any changes to the purchased hardware. As we have some machines with a high starting current or a three-phase connection, we could not use standard ShellyPlugs for this. As there are no three-phase switches available, we used a Shelly 1PM to switch a three-phase contactor. To avoid the high starting currents, we had to use a different switch. A 2log-switch was realised by using a Shelly Pro EM 50 with energy metering. Both switch variants were easy to implement thanks to the option of using ShellyOS.

To get a better impression, have a look at the attached pictures 😊

Luis and Daniel

Pictures

2.3 -

3 - Getting Started

Here you will learn step by step how to set up your own 2log instance.

Preamble

2log is a free OpenSource project that can be used freely and without charge under the terms of the GPL v.3/ AGPL v.3. This means that the authors of 2log.io do not accept any liability for any damage or infringement of valid rights caused by the use of 2log.io.

Prerequisites

In order to operate 2log, certain technical requirements must be met.

Server and Network

To run your own 2log instance, a Docker-enabled computer with x86-64 architecture is recommended. Since 2log is implemented in a very resource-efficient way, a headless Linux server with a 1.4GHz dual core and 4GB memory is sufficient.

The 2log hardware components communicate with the server via WiFi. Accordingly, the server and the IoT devices must be able to reach each other over a 2.4GHz network.

For the operation of 2log the server must be able to send e-mails. For this purpose, an SMTP mail server is required.

Machines and devices

Since the 2log Switch controls access to the devices by connecting and disconnecting power, it is important to ensure that all connected machines can handle this. Since 2log detects via power consumption whether the machine is in stand-by mode or actually working, it is ensured that a machine is never switched off from operation.

Depending on the smart sockets used for the 2log switches, it must be ensured that the machines do not draw more current than is supported by the connectors.

3.1 - Setup the 2log.io Server Application

Learn how to set up a 2log instance

The easiest way to set up your 2log instance is to use Docker.

Using Docker

The easiest way to set up your 2log instance is to use the Dockerfile provided in the repository. First, make sure that Docker is installed with the associated tool docker-compose.

mkdir ~/2log
cd ~/2log
wget https://gitlab.com/2log-io/2log.io/-/raw/main/docker/docker-compose.yaml
docker-compose up

By default, the WebAssembly frontend is served by Caddy and can be reached via port 80. If the server is running on your local machine, just visit http://localhost in your web browser and the UI should come up. The initial default login is “admin” with password “password”. Don’t forget to change the password after the first login!

Setup Mail Server

The mail server can be configured directly via the environment variables. The easiest way to define these settings is directly in the docker-compose file.

#--------- Mail Server config
#- MAIL_HOST=smtp.mydomain.com
#- MAIL_USER=admin
#- MAIL_PASS=password
#- MAIL_ADDR=2log@mydomain.com //sender eMail address
#- MAIL_CONNECTION_TYPE=TLS // or SSL or TCP
#- MAIL_SENDER=2log.io // readable sender name (optional)
#- MAIL_PORT=587
Variable Description Example
MAIL_HOST How to reach the mailserver smtp.mydomain.com
MAIL_USER The login string admin
MAIL_PASS The mail server password xF5s42F1337@r!
MAIL_ADDR Sender eMail Adesse 2log@mydomain.com
MAIL_CONNECTION_TYPE Security settings. Supported are TLS, SSL or TCP TLS
MAIL_PORT The port where the mail server is listening 587

Update from 2log.io version 1.x to 2.x

Version 2.x introduces architectural changes to how the web frontend is served. In version 1.x, the 2log container itself served the WebAssembly UI on port 8080. In version 2.x, a dedicated Caddy web server takes over the hosting of static assets (the WASM UI) and serves them on port 80. This means the docker-compose.yaml file has changed significantly and must be re-downloaded.

Step-by-step upgrade

1. Stop the running instance

cd ~/2log
docker-compose down

2. Back up your data and your current docker-compose file

cp docker-compose.yaml docker-compose.yaml.bak

All operational data is stored in ./2log.io/. It is strongly recommended to create a backup of this folder before proceeding.

3. Download the new docker-compose file

wget -O docker-compose.yaml https://gitlab.com/2log-io/2log.io/-/raw/main/docker/docker-compose.yaml

4. Transfer your mail server settings

If you had configured mail server environment variables in your old docker-compose.yaml, you need to transfer them into the new file. Open the new docker-compose.yaml and uncomment/set the corresponding environment variables under the 2log service, just like before:

environment:
    - MONGODB_HOST=mongodb
    - MAIL_HOST=smtp.mydomain.com
    - MAIL_USER=admin
    - MAIL_PASS=password
    # ... etc.

You can reference your backup file docker-compose.yaml.bak to copy over the values.

5. Keep your existing MongoDB version

mongodb:
    image: mongo:4.4.13   # keep your previous version!

6. Start the updated instance

docker-compose up -d

What changed in the new docker-compose file

Change Details
Port 8080 removed The 2log container no longer serves the web UI directly. Port 8080 is no longer mapped.
Caddy web server added A new caddy service serves the WASM frontend on port 80.
New volume ./2log.io/caddy/ The 2log container copies the Caddyfile and WASM UI files into this shared volume at startup. Caddy then serves them from there.
Custom entrypoint The 2log container now has an entrypoint script that prepares the Caddy webroot before starting the server.
restart: unless-stopped All services now automatically restart after a crash or system reboot.
MongoDB version New installations default to mongo:8. Existing installations must keep their current MongoDB version (see step 5).

Update the 2log.io instance within a major version

To get the latest features and bug fixes it is recommended to update the 2log server regularly.

Updating the 2log instance when using the Docker Compose file is very simple. Just enter the following commands in the command line:

docker-compose pull 2log
docker-compose up

Backup data

All operational data of the 2log instance is stored in the folder ./2log.io. It is strongly recommended to back up the folder at regular intervals.

3.2 - Let your community grow!

Learn how to add or import members to your 2log.io instance

To add new members you can either use the web portal or the 2log Admin app.

2log has two separate user administrations. Members and administrators are managed separately and independently. This page is only about adding members.

Add a single member

The easiest way to add a new member is via the app or web portal. The procedure is identical for both variants.

  1. Log in to your 2log instance with your admin account.
  2. Switch to the “User” menu item
  3. Click “New user”
  4. Fill in the form fields.
    • The alias field is optional. The alias must be unique and can be used by the members besides the email address to log in. If there is already a user with this alias, an error message will be displayed. The alias can also be used to call the user by his nickname.
    • The eMail address is mandatory and must be unique. If there is already a user with this email address, an error message will be displayed.
    • Currently there are three different roles: “Member”, “employee” and “guest”. Unlike “employee”, “guest” is not yet used productively. The role Employee is relevant for the machine time accounting where there is the option “Free for employees”.
  5. In the “Account balance” box, a starting balance can be set and an RFID card can be added.
    • If you use the app on an RFID-enabled smartphone, you can scan the new card directly with your phone.
    • Alternatively, the use of an “Admin Dot” is possible. This can be set up in the “Administration” area and allows convenient reading of cards from the web app.
  6. Grant access rights to individual machines or groups
  7. Click on “Create user”.

Congratulations! This is your first community member.

Add members with the CSV importer

If many users are created at once, for example when the new class starts the semester, the CSV Importer is the better choice.

  1. Log in to your 2log instance with your admin account.
  2. Switch to the “User” menu item
  3. Click “CSV Import”
  4. Download the sample template to see an example of a valid import file.
    • The importer uses the labeling of the header, i.e. the first line, to assign the individual fields. Accordingly, it does not cause any problems if additional fields or a different order is used.
  5. Upload your CSV File. You will now see a preview of the records found.
    • If no role has been assigned yet, you can assign one using the button in the header of the preview. The same applies to the group. It is possible to add a group permission to a record uploaded via CSV.
  6. Confirm the import with a click on “start import”.

3.3 -

4 - Build the Hardware Components

Here you will learn how to build the 2log hardware components.

Disclaimer

Software, schematics and building instructions were made to the best of our knowledge. We provide them here free of charge because we think it could be of use.

However, we don’t take any responsibility nor liability for using this software nor for the installation or any tips, advice, videos, etc. given by any member of this site or any related site.

4.1 - Build a 2log Dot

Learn how to build a 2log Dot

The 2log Dot is a smart RFID reader that can read almost all common RFID cards. Its main purpose is to allow users to authenticate themselves with their smart cards in the system. For example, to log on to a machine.

The 2log Dot is based on the ESP32 and the PN532, two components that are used very often in the maker scene and are easy to obtain. Thanks to the modular design and the exposed GPIO pins, the 2log Dot can be extended at will.

The PCB

The 2log Dot board is a joint project which was developed together with the Technik Kultur Saar e.V. - Many thanks to Matthew for this contribution! In this repository you will find Gerber files for the 2log Dot board.

Order the PCB

  1. Go to https://jlcpcb.com
  2. Click on “Instant Quote”
  3. Click on “Add gerber file” and upload the .zip file you can get from here .
  4. Do a few necessary changes (let the other settings as it is):
    • Choose the number of pieces (Quantity)
    • Choose your favorite PCB Color - We prefer black ;)
    • Select the appropriate Layers:
      • L1: 2logDot-F_Cu.gbr
      • L2: 2logDot-In1_Cu.gbr
      • L2: 2logDot-In2_Cu.gbr
      • L2: 2logDot-B_Cu.gbr
  5. Proceed with the checkout and complete the order.

Congratulations - in a few days you will have your 2log Dot boards in your hands!

Get the Parts

The PCB consists of a 4-Layer stack. All required parts are through hole components with the exception of the capacitor C1 which is a combined footprint. Besides the PCB itself you need the following parts:

  • 24 Led WS2812B Ring with 4 contacts (diameter 66mm)
  • SMD Capacitor 5mm diameter, about 10uF
  • (alternative) THT Capacitor, about 10uF
  • Wemos D1 mini ESP32 (ESP8266 will not work)
  • PN532 RFID Reader V3 (red modules, sold under elechouse brand or clones)
  • mini pushbutton (the tiny black/silver ones)
  • (optional) 14 Pin Male and 13 Pin Female 2.54mm Pin Header/Socket for expansion port

Renderings

Assembling

To build a Dot you need a soldering iron with a fine tip, solder and some stranded wire.

I highly recommend using the template that can be clamped between the reader and PCB. This ensures that the LED sits above the PN532. This avoids ugly shadows. you can find the stl file here: https://gitlab.com/2log-io/hardware/2log-dot-case

It’s a good idea to put the ESP loose on the pins first, while soldering the pins tight to the board. This ensures that the ESP can be plugged in later without any problems when it is time for its turn. gi

Next, the button can be soldered on.

Solder the pins to the PN532. Also here it makes sense to insert the pins loosely into the board during soldering. Otherwise it can happen that you solder the pins a little bit crooked. Then they no longer fit into the PCB and you have trouble.

Now you can connect the reader to the board. In between comes the template that we printed out earlier with the 3D printer. Make sure that the recess in the template is positioned so that you have free access to the pins for the LED ring.

Now we can solder the capacitor and take the opportunity to cut off the protruding pins of the PN532.

Next, the ESP can be soldered.

Now we can work on the LED ring. For this I took copper wire and stripped it. Next, the stranded wire is tinned and soldered to the contacts of the LED ring.

Bend the pins upwards and put the ring on the template. Here you have to thread the stranded wire through the holes of the board and solder it from the backside.

Congratulations! You now have a 2log Dot.

The case

The case can be printed with normal PLA. Get the stl files from here. I particularly like the matte look of the Extrudr NX2 black matte. For the lid, simply laser a circle with a diameter of 70.5 mm. The material used for this is BLACK & WHITE 9H04 SC.

Flash the Firmware

The easiest way to flash the firmware is using the 2log Dot Web Flasher. No tools or drivers need to be installed — just a compatible browser (Chrome, Edge, or Firefox).

  1. Connect the Dot via Micro-USB cable to your PC.
  2. Open the Web Flasher in your browser.
  3. Click Flash Firmware and select the serial port of the ESP32.
  4. Wait until the flashing process is complete.

Option 2: Command Line

If you prefer flashing via the command line, you can use esptool.py:

  1. Make sure that the drivers for the serial adapter of your ESP32 and the Python tool “esptool.py” is installed.
  2. Then download the latest firmware build from our CI Toolchain here: https://gitlab.com/2log-io/2log-dot/-/jobs/artifacts/main/download?job=build
  3. Connect the dot with a micro usb cable to your PC and flash the binaries with the following command to your ESP:
esptool.py  \
            -b 460800 \
            --before=default_reset \
            --after=hard_reset write_flash \
            --flash_mode dio \
            --flash_freq 40m \
            --flash_size 4MB \
            0x1000 bootloader/bootloader.bin \
            0x10000 2log-Dot.bin \
            0x8000 partition_table/partition-table.bin \
            0xe000 ota_data_initial.bin

You may need to add -p /dev/<serial-adapter> with the path to the serial adapter in case the system can’t detect the serial adapter automatically.

Connect the Dot with your 2log instance

You can set up the devices either with the 2log app or manually with a Linux Shell. Using the app is straight forward and will be explained in the corresponding chapters.

Provisioning without mobile app

Here we explain how to provision a Dot via a direct SSH connection. You only need a command line for the manual setup.

You can also use this protocol to create your own program code for provisioning.

  1. Press the button on the back of the Dot with a pointed object for several seconds. Once the Dot is in pairing mode, it will start glowing purple and open a WiFi hotspot.

  2. Connect your laptop to the WiFi with the SSID I'm a Dot.

  3. Enter the following command into your linux console:

openssl s_client -connect 192.168.4.1:8443

After a few console outputs, a connection to the Switch should be established.

  1. Send the following JSON command to the device by typing it into the console and confirming with return:
 {"cmd": "hi"}

The device will respond with something similar to

{
	"cmd":	"welcome",
	"device":	{
		"sid":	"I5O2",
		"uuid":	"3C:61:05:DE:8A:A4"
	}
}

Write down the short id (sid) somewhere. You will need it later to assign the device. In the example here the device has the sid I502

  1. Now we can send the configuration to the device with the following JSON command
{
   "cmd":"setconfig",
   "ssid":"<YOUR_SSID>",
   "pass":"<YOUR_PASSWORD>",
   "extconfig":{
      "server":"<YOUR_2LOG_SERVER>",
      "testconfig":false
   }
}
  1. The device will respond with
{ "cmd":"setconfig","status":1}

Which means that the device has received the data.

  1. The device will now reboot and try to connect to the server. The Dot will stop glowing once it is successfully connected to the 2log instance. Now you can assign a function to the Dot using the four-digit short ID.

4.2 - Build a 2log Switch

Learn how to build a 2log Switch

The 2log Switch is a smart wireless socket that can switch power and measure energy consumption. It communicates via WiFi with the 2log server and ensures that only authorized users can use the machines. By measuring the power consumption, the system knows exactly how long the machine has been in use.

The new generation of Shelly devices comes with Shelly OS, which is fortunately very open and comes with well-documented APIs. In addition, the Shelly smart meters already support outgoing websocket connections out of the box, making them perfect for use with 2log.

Before you start, make sure that your 2log instance is up to date. The endpoint for Shelly sockets waits on port 4712 for incoming websocket connections. If you are using Docker, make sure that docker-compose.yaml is configured accordingly.

  1. Log in to the web portal of the Shelly device and carry out a firmware update.
  2. Connect the Shelly socket to the Wifi network via which the 2log server is accessible.
  3. Configure an “outbound websocket” connection. Enter the IP address of the 2log server. Do not forget to enter the port 4712. The address then looks something like this: ws://<2log IP>:4712.
  4. Log in to the 2log admin interface, go to the device explorer in the settings area.
  5. The switch should appear here in the “Unregistered Devices” area. Make a note of the short ID. You will need it later to assign the switch to a machine.
  6. Go to the settings of your 2log resource. Click on “Set up now” for the switch. You can answer the question as to whether the device is already connected to the network with “Yes”. Now use the short ID to assign the new Shelly to the machine.
  7. Now configure the switch via the web interface so that it is not publicly accessible. For example, by assigning a password and deactivating the public access point if necessary.

Shelly Plug S and Shelly 1PM (deprecated)

To use an Shelly Plug S or a Shelly 1 PM (the older models, not the PLUS version!) as a 2log switch, the 2log firmware must be flashed manually. This process is a little fiddly, not entirely trivial and fortunately no longer necessary thanks to the new generation of Shelly devices. However, if you have this hardware available and are not afraid of the effort, you can get started right away. The only thing you need is an FTDI / Serial Programmer and possibly a soldering iron with a fine tip.

Flashing the Firmware

Officially supported are currently the models “Shelly Plug S” and “Shelly 1PM”. Regarding the 1PM, you have to be careful not to accidentally buy the plus version with the square case. We need the version with the ESP8266 and the round case.

To flash a Shelly Plug S socket you have to do the following steps:

  1. Download the firmware binaries from our CI Pipeline
  2. Connect the serial programmer
    • PlugS:
    • 1PM:
      • Remove the rubber cap
      • Connect the Serial Programmer as described in the manual.
  3. Flash the firmware with esptool
    esptool.py \
        --chip esp8266 \
        --port /dev/tty.usbserial-UUT1 \
        --baud 230400 \
        --before default_reset \
        --after hard_reset write_flash \
        -z \
        --flash_mode dio \
        --flash_freq 40m \
        --flash_size 4MB \
        0x0 build/bootloader/bootloader.bin \
        0x10000 build/2log-switch.bin \
        0x8000 build/partitions-OTA-2MB.bin
    

Connect the Switch with your 2log instance

You can set up the devices either with the 2log app or manually with a Linux Shell. Using the app is straight forward and will be explained in the corresponding chapters.

Provisioning without mobile app

Here we explain how to provision a Switch via a direct SSH connection. You only need a command line for the manual setup.

You can also use this protocol to create your own program code for provisioning.

  1. Press the button of the Switch for several seconds. Once the Dot is in pairing mode, it will start blinking slowly and open a WiFi hotspot.

  2. Connect your laptop to the WiFi with the SSID I'm a Switch.

  3. Enter the following command into your linux console:

openssl s_client -connect 192.168.4.1:8443

After a few console outputs, a connection to the Switch should be established.

  1. Send the following JSON command to the device by typing it into the console and confirming with return:
 {"cmd": "hi"}

The device will respond with something similar to

{
	"cmd":	"welcome",
	"device":	{
		"sid":	"I5O2",
		"uuid":	"3C:61:05:DE:8A:A4"
	}
}

Write down the short id (sid) somewhere. You will need it later to assign the device. In the example here the device has the sid I502

  1. Now we can send the configuration to the device with the following JSON command
{
   "cmd":"setconfig",
   "ssid":"<YOUR_SSID>",
   "pass":"<YOUR_PASSWORD>",
   "extconfig":{
      "server":"<YOUR_2LOG_SERVER>",
      "testconfig":false
   }
}
  1. The device will respond with
{ "cmd":"setconfig","status":1}

Which means that the device has received the data.

  1. The device will now reboot and try to connect to the server. The Switch will stop blinking and glow continuously once it is successfully connected to the 2log instance. Now you can assign a function to the Dot using the four-digit short ID.

5 - Machine Control

Here you will learn how to integrate a machine into 2log.io

One of the main functions of 2log is the access control of machines. A machine can be any device with a power cable. From the laser cutter to the band saw to the 3D printer, pretty much any device can be integrated.Thanks to 2log rights management, each user can be given permission to use specific machines. This is done either via individual permissions or via groups.

Via the power consumption, 2log can determine whether a machine is actually working or only in stand-by mode. In this way, the machine usage can be charged according to different pricing models.

Prerequisities

Certain hardware and software components are required to set up a machine access control.

The machine itself

Since the 2log Switch controls access to the devices by connecting and disconnecting power, it is important to ensure that all connected machines can handle this. Since 2log detects via power consumption whether the machine is in stand-by mode or actually working, it is ensured that a machine is never switched off from operation.

Depending on the smart sockets used for the 2log switches, it must be ensured that the machines do not draw more current than is supported by the smart plugs.

Needed Hardware

To integrate a machine into 2log, two hardware components are required: A 2log Switch and a 2log Dot. The Dot is a smart RFID reader that reads the user’s cards and logs them into the machine. The Swtich is the actuator. It activates the power supply only when a user with valid authorization has logged on to the system.

Used Software

The 2log Admin App is required to connect the hardware components with the 2log.io server. The APK for Android can be downloaded here

5.1 - Setup a Machine Control Instance

Learn how to setup a machine control by connecting Switch and Dot with the 2log system.

Create a new Machine

Connecting the hardware components to the server must be done via the 2log app. This is currently only available for Android. The APK can be downloaded here. For this reason, it is recommended to run the complete setup of the new machine directly via the app.

  1. Log in to your 2log instance with your admin account.
  2. Go to “Resources” and click on “Add” in the “Access control” box in the upper right corner
  3. Enter a unique and preferably unambiguous name for the machine in the small pop-up window and then click on the “+” symbol.
  4. The new machine should now appear as a tile. You will then be taken directly to the machine settings overview page.

Connet a Dot

In the machine settings there is a box with the heading “Dot”. Immediately after creating the machine, a note should appear here stating that no dot has yet been assigned.

  1. Click on “Set up now”
  2. Now you will be asked if you want to use a dot that was already used in the system or if you want to use a new dot.

Setup a new Dot

If you are setting up a new machine you will probably want to connect a new Dot.

  1. Answer “no” to the question whether the Dot is already connected to the system. You will now be redirected to the Setup Wizard.

  2. Follow the instructions dosplayed on the screen until the setup is complete.

  3. If the setup is completed successfully, you have the possibility to test the connection by clicking on the “Blink” button. If the LEDs of the dot start blinking, everything has worked.

Setup an already connected Dot

If it is a Dot that is already connected to the server, continue here.

  1. Answer “yes” to the question whether the Dot is already connected to the system.

  2. Enter the four character address of the dot you want to assign to the machine.

  3. If the setup is completed successfully, you have the possibility to test the connection by clicking on the “Blink” button. If the LEDs of the dot start blinking, everything has worked.

Connect a Switch

In the machine settings there is a box with the heading “Switch”. Immediately after creating the machine, a note should appear here stating that no switch has yet been assigned.

  1. Click on “Set up now”
  2. Now you will be asked if you want to use a switch that was already used in the system or if you want to use a new switch.

Setup a new Switch

If you are setting up a new machine you will probably want to connect a new Switch.

  1. Answer “no” to the question whether the Switch is already connected to the system. You will now be redirected to the Setup Wizard.

  2. Follow the instructions dosplayed on the screen until the setup is complete.

Setup an already connected Switch

If it is a Switch that is already connected to the server, continue here.

  1. Answer “yes” to the question whether the switch is already connected to the system.

  2. Enter the four character address of the switch you want to assign to the machine.

5.2 - Configure a Machine Control

Learn how to configure an access control by setting the current threshold and defining the pricing model.

To access the settings page of a machine control:

  1. click on “Resources” in the main menu
  2. click on the machine you want to configure in the “Access Control” box.
  3. click on “Settings” in the upper right corner

General settings

Display Name

Sets the name with which the machine is displayed in the system. The name should be unique and identify the machine without any doubt.

Bad example: “3D Printer 1” , “3D Printer 2”, “3D Printer 3”.

Good example: “Prusa i3MK3s orange”, ““Prusa i3MK3 black”, “Ultimaker 2”

Switch off after …

Defines after which period of time (in minutes) a machine is automatically switched off if no active job is currently running. This also automatically causes the currently logged in user to be logged out.

Type

Select a machine type. This currently only affects the icon that is displayed in the overview page.

Suction

Many machines require suction to extract sawdust or toxic fumes. But some of them are not able to communicate with the machines they are connected to.

2log offers the possibility to switch a suction with a 2log Switch and assign it to one or more machines. If a user logs on to a machine that is connected to a suction, the suction will automatically switch on. This is especially helpful when several machines share one suction.

Pricing

2log offers different pricing models for charging the machine usage. A distinction is made between billing on the basis of machine usage or on the basis of user session. The distinction which billing basis makes more sense depends primarily on the type of machine. Machines whose jobs have a predefined runtime, such as laser cutters or 3D printers, should be billed according to the duration of use. Machines such as belt grinders or drill presses are better billed according to the session. This prevents the user from switching the machine on and off unnecessarily often.

Regardless of the billing basis, you can choose between a flat fee or billing by duration. The duration of a unit can be freely defined.

According to duration of use

When billing according to the duration of use, only the time during which the machine is actually running is charged.

Flat rate per job

With “Flat rate per job”, the set fee is charged as a flat rate for each time the machine is switched on.

Flat rate per session

In the case of a flat rate per session, the set fee is charged only once for logging on to the machine.

By session time

When billing by session time, the time during which the user is logged in to the machine is billed.

Threshold adjustment

When charging on the basis of machine usage (job duration or flat rate per job), it is very important to set the threshold value to match the machine behavior.

  1. Turn on the machine and let it run in stand-by mode for a few minutes.

  2. Start a job and wait until it has run through or switch on the machine and let it work for some time. You should see the power consumption of the machine in the form of a graph.

  3. Move the threshold with the mouse so that the graph is above the line most of the time during operation.

6 - The 2log.io Mobile Apps

Here you will learn step by step how to set up your own 2log instance.

Overview

2log.io provides two mobile apps. One is the Community App, which allows members to perform transactions or log on to machines by scanning QR codes. The other is the Operator App, which allows easy administration and management of the 2log instance.

6.1 - The 2log App for Community Members

Here you will learn step by step how to set up your own 2log instance.

What’s the Idea of the App?

Not everyone likes to carry another smart card. The 2log app for community members provides an alternative to the RFID card. Once the app is linked to your 2log account, just scan the RFID code displayed to authenticate yourself. In addition, the app allows you to keep track of your account balance and transactions.

Where can I get the app?

The Community App is available for Android and soon also for iOS in the AppStore. You will find all further information at https://2log.io/users/

Where can the app be used?

Currently, the app only works with the virtual tally sheet. However, we are already working on an alternative 2log Dot version with a small OLED display. The goal is to make all 2log services compatible with the app as well.

Privacy Policy

The 2log app for community members as such does not store any personal data. However, every action performed with the app (e.g. payment or login processes) could be logged on the server side. Since each operator of a 2log instance is responsible for the collection, storage and processing of data, no generally valid statement can be made here about the storage and processing of data.

Finally, it depends on the infrastructure of the instance operator which data is stored and for which purposes it is processed. Please contact the operator of the instance for further information.

7 - REST API

Use the 2log REST API to manage users, groups, permissions and logs programmatically.

The 2log REST API allows you to manage your instance programmatically. This is useful for automating recurring tasks, integrating 2log with other systems, or building your own tools on top of it.

All examples in this section use curl and assume your 2log server is reachable at http://your-server. The Caddy reverse proxy forwards everything under /api to the QuickHub REST backend, so all API endpoints are prefixed with /api.

How the REST API works

Under the hood, 2log is built on the QuickHub framework. QuickHub provides real-time data synchronization over WebSockets. Resources (such as the user list or a device configuration) live on the server and are identified by a resource path like labcontrol/users.

The REST API gives you plain HTTP access to these same resources. Since slashes in URLs would be interpreted as path separators, the REST API uses dots as namespace separators in the URL. The server translates dots back to slashes internally:

URL path component Internal resource path
labcontrol.users labcontrol/users
labcontrol.groups labcontrol/groups
labcontrol.users.groups.{uuid} labcontrol/users/groups/{uuid}

Resource types

The REST API exposes three types of endpoints, each mapping to a different QuickHub resource type:

Endpoint prefix Resource type Description
/api/lists/{resource} Synchronized List Ordered collections of items (e.g. users, groups, permissions). Supports GET, POST, PUT, PATCH, DELETE.
/api/objects/{resource} Object Key-value stores (e.g. the current user’s profile). Supports GET, PUT, PATCH.
/api/services/{service}/{method} Service RPC-style function calls (e.g. addUser, getLogs). Always uses POST.

Additionally, there are endpoints for binary data:

Endpoint prefix Description
/api/images/{resource} Upload, list and download images.
/api/files Generic file upload and download.

The following pages explain each area in detail.

7.1 - Authentication

How to log in, manage session tokens, and log out via the REST API.

Before you can use the API, you need to log in with your admin account. The login endpoint returns a session token that you include in all subsequent requests.

Log in

curl -s -X POST http://your-server/api/login \
  -H "Content-Type: application/json" \
  -d '{"user": "admin@fablab.org", "pass": "your-password"}'

The server responds with a token:

{"token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}

For convenience, you can store the token in a shell variable:

TOKEN=$(curl -s -X POST http://your-server/api/login \
  -H "Content-Type: application/json" \
  -d '{"user": "admin@fablab.org", "pass": "your-password"}' | jq -r '.token')

Providing the token

Include the token in every request. The server accepts it in three places (checked in this order):

  1. Authorization header (recommended):
    Authorization: Bearer $TOKEN
    
  2. Session cookie (set automatically after login if you preserve cookies)
  3. Query parameter (fallback):
    ?token=$TOKEN
    

Already logged in

If the session cookie already contains a valid token, a second login request returns the existing token without creating a new session.

Log out

When you are done, invalidate the session:

curl -X POST http://your-server/api/logout \
  -H "Authorization: Bearer $TOKEN"

Response:

{"success": true}

Error responses

Situation Status Message
Missing user or pass 400 Missing credentials
Unknown user 401 User not found
Wrong password 401 Incorrect password
Account not allowed 403 Permission denied
Expired or invalid token (on other endpoints) 403 Invalid token. Please log in and try again.

API tokens

For automated or long-running integrations you can create API tokens instead of using session-based login. API tokens are managed through the admin UI and can be used directly as bearer tokens — no login step required.

Creating an API token

  1. Open the Admin panel in the 2log UI.
  2. Navigate to the API Tokens section.
  3. Provide a name, an optional description, permissions, and an optional expiration date.
  4. Click Create. The token string is shown once — copy and store it securely.

Using an API token

Use the token exactly like a session token. The server accepts it in the same three places:

# Authorization header (recommended)
curl http://your-server/api/some-endpoint \
  -H "Authorization: Bearer <API_TOKEN>"

# Query parameter
curl "http://your-server/api/some-endpoint?token=<API_TOKEN>"

Key differences from session tokens

Session token API token
Created via POST /api/login Admin UI
Lifetime Expires on session timeout Valid until expiration date (or indefinitely if none is set)
Scope Full admin access Configurable permissions
Revocation POST /api/logout Delete in Admin UI

7.2 - Managing Users

Create, read, update and delete users via the REST API.

User list (admin)

Users are stored as a synchronized list resource at labcontrol.users. You need LAB_ADMIN, IS_ADMIN, or LAB_SEE_USERS permissions to access this resource.

List all users

curl http://your-server/api/lists/labcontrol.users \
  -H "Authorization: Bearer $TOKEN"

The response is a JSON array. Each item contains a data object with the user fields and a uuid at the top level:

[
  {
    "data": {
      "name": "Max",
      "surname": "Mustermann",
      "mail": "max@fablab.org",
      "alias": "maxm",
      "role": "mem",
      "course": "",
      "balance": 1500,
      "creditLimit": -1,
      "state": 1,
      "lastLogin": "2024-01-15T10:30:00.000",
      "creation": "2023-06-01T08:00:00.000",
      "uuid": "f47ac10b58cc4372a5670e02b2c3d479"
    },
    "uuid": "f47ac10b58cc4372a5670e02b2c3d479"
  }
]

Field reference:

Field Type Description
name string First name
surname string Last name
mail string Email address
alias string Display name (chosen by user)
role string mem (member), empl (employee), ext (external/guest)
course string Course or semester (e.g. WS2024)
balance int Account balance in cents
creditLimit int Maximum negative balance in cents. -1 = use global default
state int 0 = idle, 1 = active, 2 = disabled, 3 = deleted
lastLogin string ISO 8601 timestamp of last login
creation string ISO 8601 timestamp of account creation
uuid string Unique user ID

Get a single user

By UUID:

curl http://your-server/api/lists/labcontrol.users/f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN"

By index (0-based position in the list):

curl http://your-server/api/lists/labcontrol.users/0 \
  -H "Authorization: Bearer $TOKEN"

Update user properties

To change individual properties of an existing user, use PATCH. Only the fields you specify are changed:

curl -X PATCH http://your-server/api/lists/labcontrol.users/f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "role": "empl"
    }
  }'

Replace a user record

If you want to replace the entire user object, use PUT:

curl -X PUT http://your-server/api/lists/labcontrol.users/f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "name": "Max",
      "surname": "Mustermann",
      "mail": "max@fablab.org",
      "role": "empl",
      "balance": 3000
    }
  }'

Remove a user

curl -X DELETE http://your-server/api/lists/labcontrol.users/f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN"

Add a user via the lab service

To create a new user with permissions, cards, and group assignments in one step, use the lab service. This is the recommended way to add users because it handles all related data at once. You need LAB_ADMIN or LAB_MODIFY_USERS permissions.

curl -X POST http://your-server/api/services/lab/addUser \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "user": {
      "name": "Lisa",
      "surname": "Lasercut",
      "mail": "lisa@fablab.org",
      "role": "mem"
    },
    "permissions": {},
    "card": {},
    "groups": {}
  }'

To create a user or update them if they already exist (useful for CSV imports), use addOrUpdateUser:

curl -X POST http://your-server/api/services/lab/addOrUpdateUser \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "user": {
      "name": "Lisa",
      "surname": "Lasercut",
      "mail": "lisa@fablab.org",
      "role": "mem"
    },
    "permissions": {},
    "card": {},
    "groups": {}
  }'

Delete a user via the lab service

curl -X POST http://your-server/api/services/lab/deleteUser \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"userID": "f47ac10b58cc4372a5670e02b2c3d479"}'

Transfer money

To add or deduct credit from a user’s balance, use the transferMoney method. The value is in cents (positive = credit, negative = debit). Requires LAB_ADMIN or LAB_SERVICE permissions.

curl -X POST http://your-server/api/services/lab/transferMoney \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "value": 500,
    "description": "Workshop fee refund"
  }'
Parameter Type Required Description
userID string yes UUID of the user
value int yes Amount in cents
description string no Reason for the transfer

Reset a user’s password

Sends a temporary password to the user by email:

curl -X POST http://your-server/api/services/lab/resetPassword \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"userID": "f47ac10b58cc4372a5670e02b2c3d479"}'

Look up a user by card ID

Requires LAB_ADMIN, LAB_SERVICE, or LAB_SEE_USERS permissions.

curl -X POST http://your-server/api/services/lab/getUserForCard \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"cardID": "04:A3:2B:1C:D4:E5:F6"}'

Look up a user by external reference

If users are linked to an external system via extRef, you can look them up:

curl -X POST http://your-server/api/services/lab/getUserForExternalReference \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"extRef": "EXT-12345"}'

Response:

{
  "errorCode": 0,
  "userID": "f47ac10b58cc4372a5670e02b2c3d479",
  "userName": "Max",
  "eMail": "max@fablab.org",
  "balance": 1500
}

If no user is found, errorCode is -1.

Reading your own user data

To read the data of the currently logged-in user as an object resource, use labcontrol.user (singular). This does not require admin permissions.

curl http://your-server/api/objects/labcontrol.user \
  -H "Authorization: Bearer $TOKEN"

The response wraps each property in a data field:

{
  "name": {"data": "Max"},
  "surname": {"data": "Mustermann"},
  "mail": {"data": "max@fablab.org"},
  "alias": {"data": "maxm"},
  "role": {"data": "mem"},
  "balance": {"data": 1500},
  "state": {"data": 1},
  "creditLimit": {"data": -1},
  "course": {"data": ""},
  "lastLogin": {"data": "2024-01-15T10:30:00.000"},
  "creation": {"data": "2023-06-01T08:00:00.000"},
  "uuid": {"data": "f47ac10b58cc4372a5670e02b2c3d479"}
}

Read a single property

curl http://your-server/api/objects/labcontrol.user/balance \
  -H "Authorization: Bearer $TOKEN"

Update your own profile

Regular users can only modify their alias:

curl -X PUT http://your-server/api/objects/labcontrol.user/alias \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data": "my-new-alias"}'

Admins (LAB_ADMIN, IS_ADMIN, or LAB_MODIFY_USERS) can additionally modify name, surname, mail, role, course, creditLimit, and extRef.

7.3 - Resources (Machines)

Read and manage resource controllers, their aspects (billing, QR code, permissions, etc.) via the REST API.

Resources represent the logical machines and devices managed by 2log (e.g. a laser cutter, a 3D printer, or a suction system). Each resource is a bundle that combines a controller, a resource state, and a set of aspects that add capabilities like billing, logging, or QR code authentication.

Permissions

  • Admins (IS_ADMIN): full read/write access to all resource objects and properties.
  • All authenticated users: read-only access to a subset of public properties (see below).

Resource list

All resources are stored as a synchronized list at 2log.resources. This list is readable by any authenticated user, but only admins can add or remove entries.

List all resources

curl http://your-server/api/lists/2log.resources \
  -H "Authorization: Bearer $TOKEN"

The response is a JSON array. Each item contains a data object with the resource properties and a uuid:

[
  {
    "data": {
      "displayName": "Laser Cutter",
      "resourceUid": "laser-cutter-01",
      "systemType": "machines",
      "controllerType": "genericPrimaryBundle",
      "controllerState": 0,
      "resourceState": 0,
      "userName": "",
      "userType": "",
      "bundleType": "genericPrimaryBundle"
    },
    "uuid": "laser-cutter-01"
  }
]

Public properties (visible to all authenticated users):

Field Type Description
displayName string Human-readable name of the resource
controllerState int Current state of the controller
systemType string Resource category (e.g. machines, suctions)
userType string User-facing machine type label (free-form, e.g. Lasercutter, 3D-Drucker). Unlike systemType, this is a display label that can be chosen freely.
resourceUid string Unique resource identifier

Admin-only properties (additionally visible to admins):

Field Type Description
controllerType string Bundle type (e.g. genericPrimaryBundle, prusa3DPrinterBundle)
resourceState int Current resource state
userName string Name of the currently logged-in user
bundleType string Bundle type identifier

Get a single resource

curl http://your-server/api/lists/2log.resources/laser-cutter-01 \
  -H "Authorization: Bearer $TOKEN"

Resource objects (admin only)

Each resource bundle and its sub-components are also available as individual object resources. These endpoints require IS_ADMIN permission.

Resource bundle

Returns all properties of a resource bundle as an object:

curl http://your-server/api/objects/2log.resources.laser-cutter-01 \
  -H "Authorization: Bearer $TOKEN"

The response wraps each property in a data field (standard QuickHub object format):

{
  "displayName": {"data": "Laser Cutter"},
  "resourceUid": {"data": "laser-cutter-01"},
  "systemType": {"data": "machines"},
  "controllerType": {"data": "genericPrimaryBundle"},
  "controllerState": {"data": 0},
  "resourceState": {"data": 0},
  "userName": {"data": ""},
  "userType": {"data": ""},
  "imageScale": {"data": 1.0},
  "imageCenterX": {"data": 0},
  "imageCenterY": {"data": 0}
}

Resource sub-object

Returns the resource state object:

curl http://your-server/api/objects/2log.resources.laser-cutter-01.resource \
  -H "Authorization: Bearer $TOKEN"

Controller sub-object

Returns the controller state object:

curl http://your-server/api/objects/2log.resources.laser-cutter-01.controller \
  -H "Authorization: Bearer $TOKEN"

Aspects

Aspects are modular capabilities attached to a resource. Each aspect is accessible as an object resource at 2log.resources.{resourceUid}.{aspectName}. All aspect endpoints require IS_ADMIN permission.

The available aspects depend on the bundle type:

Aspect name genericPrimaryBundle prusa3DPrinterBundle genericSecondaryBundle Description
billing yes yes Usage-based billing
dblogs yes yes Database logging
permissioncheck yes yes Permission validation
dot yes yes 2log Dot hardware enabler
qrcode yes yes QR code authentication
secondary yes Companion/secondary resource control

billing – Usage-based billing

The billing aspect controls how usage of a resource is charged.

curl http://your-server/api/objects/2log.resources.laser-cutter-01.billing \
  -H "Authorization: Bearer $TOKEN"

Properties:

Property Type Description
payingMode int Billing mode (see table below)
pricePerUnit int Price per unit in cents
unitDuration int Duration of one billing unit (in seconds)
employeesForFree bool If true, employees (empl role) are not charged
minimumCreditBalance int Minimum credit balance required to start a session (in cents)

Billing modes (payingMode):

Value Mode Description
0 DISABLED No billing
1 BILLING_BY_SESSION_TIME Charged based on total session time
2 BILLING_BY_PRODUCTIVE_TIME Charged based on productive (active) time only
3 BILLING_PER_JOB Flat fee per job
4 BILLING_WHEN_ENABLED Charged upon activation

To update billing settings:

curl -X PUT http://your-server/api/objects/2log.resources.laser-cutter-01.billing/payingMode \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data": 1}'

qrcode – QR code authentication

The QR code aspect manages how users authenticate at a machine using QR codes (scanned via the 2log mobile app).

curl http://your-server/api/objects/2log.resources.laser-cutter-01.qrcode \
  -H "Authorization: Bearer $TOKEN"

Properties:

Property Type Description
mode int QR code mode (see table below)
code string Current QR code value

QR code modes (mode):

Value Mode Description
0 DISABLED QR code authentication is off
1 STATIC A fixed QR code is used (defaults to the resource UID)
2 DYNAMIC The server generates a new random code (12 characters) periodically

Reading the current QR code

To read the current QR code value for a machine:

curl http://your-server/api/objects/2log.resources.laser-cutter-01.qrcode/code \
  -H "Authorization: Bearer $TOKEN"
{"data": "A3xK9mP2qR7w"}

In static mode the code value stays the same (typically the resourceUid). In dynamic mode the server generates a new 12-character code automatically. To get the current code, simply read this property – the server always returns the currently valid value.

Changing the QR code mode

curl -X PUT http://your-server/api/objects/2log.resources.laser-cutter-01.qrcode/mode \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data": 2}'

dblogs – Database logging

The logging aspect tracks resource usage and writes log entries to the database.

curl http://your-server/api/objects/2log.resources.laser-cutter-01.dblogs \
  -H "Authorization: Bearer $TOKEN"
Property Type Description
dbref string Database reference identifier for this resource’s logs

This aspect works together with the billing aspect: when a session ends, the billing information is automatically written as a log entry. The resulting logs can be queried via the getLogs service method.

permissioncheck – Permission validation

The permission check aspect verifies whether a user has the required permissions to use a resource. It works asynchronously – when a user attempts to authenticate, it queries the configured permission service and returns the result.

curl http://your-server/api/objects/2log.resources.laser-cutter-01.permissioncheck \
  -H "Authorization: Bearer $TOKEN"

secondary – Companion resource control

The companion controller aspect links a primary resource to a secondary resource (e.g. linking a suction system to a laser cutter so that the suction starts automatically).

curl http://your-server/api/objects/2log.resources.laser-cutter-01.secondary \
  -H "Authorization: Bearer $TOKEN"

Properties:

Property Type Description
resourceUid string UID of the linked secondary resource
interceptWhenNotRunning bool Block the primary resource if the secondary is not running
desiredResourceState int Target state for the secondary resource
forceInterception bool Force interception regardless of state
ready bool Whether the secondary resource is ready

dot – 2log Dot hardware enabler

The Dot aspect integrates with the physical 2log Dot device (an NFC/RFID reader attached to the machine).

curl http://your-server/api/objects/2log.resources.laser-cutter-01.dot \
  -H "Authorization: Bearer $TOKEN"
Property Type Description
dotDeviceMapping string Mapping identifier for the associated Dot hardware device

Aspect lists

You can retrieve a flat list of all aspects of a given type across all resources. This is useful for getting an overview (e.g. all billing configurations or all QR codes at once).

The endpoint is a synchronized list at 2log.resources.{aspectType}:

# Get all billing aspects across all resources
curl http://your-server/api/lists/2log.resources.billing \
  -H "Authorization: Bearer $TOKEN"

# Get all QR code aspects across all resources
curl http://your-server/api/lists/2log.resources.qrcode \
  -H "Authorization: Bearer $TOKEN"

The valid aspect type values are: billing, dblogs, permissioncheck, secondary, dot, qrcode.


Creating and deleting resources

Resources are managed via the resources service. See the Service Reference for details.

Create a resource

curl -X POST http://your-server/api/services/resources/newController \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Laser Cutter",
    "type": "machines",
    "uid": "laser-cutter-01"
  }'

Delete a resource

curl -X POST http://your-server/api/services/resources/deleteController \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"uid": "laser-cutter-01"}'

7.4 - Groups and Permissions

Manage groups, individual permissions and RFID cards via the REST API.

Managing groups

Groups are stored as a synchronized list resource at labcontrol.groups. You need LAB_ADMIN, IS_ADMIN, or LAB_SEE_GROUPS permissions to read groups and LAB_MODIFY_GROUPS to modify them.

List all groups

curl http://your-server/api/lists/labcontrol.groups \
  -H "Authorization: Bearer $TOKEN"
[
  {
    "data": {
      "name": "Woodworking",
      "description": "Access to all woodworking machines",
      "systemGroup": false,
      "entities": [],
      "uuid": "a1b2c3d4e5f67890abcdef1234567890"
    },
    "uuid": "a1b2c3d4e5f67890abcdef1234567890"
  }
]

The system automatically creates three system groups for the built-in roles mem, empl, and ext. Groups with systemGroup: true should not be modified manually.

Create a new group

curl -X POST http://your-server/api/services/lab/addGroup \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Electronics Lab",
    "description": "Access to soldering stations and measurement equipment"
  }'

Requires LAB_ADMIN, LAB_SERVICE, or LAB_MODIFY_GROUPS.

Update group properties

curl -X PATCH http://your-server/api/lists/labcontrol.groups/a1b2c3d4e5f67890abcdef1234567890 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "description": "Access to all woodworking and CNC machines"
    }
  }'

Delete a group

curl -X DELETE http://your-server/api/lists/labcontrol.groups/a1b2c3d4e5f67890abcdef1234567890 \
  -H "Authorization: Bearer $TOKEN"

Group entities (machines in a group)

Each group has a nested list of entities (the machines and resources it grants access to). This list is accessible at labcontrol.groups.entities.{groupUUID}:

curl http://your-server/api/lists/labcontrol.groups.entities.a1b2c3d4e5f67890abcdef1234567890 \
  -H "Authorization: Bearer $TOKEN"
[
  {
    "data": {
      "resourceID": "laser-cutter-01",
      "type": 0,
      "active": true,
      "expires": false,
      "expirationDate": "",
      "creationDate": "2024-01-10T14:00:00.000"
    },
    "uuid": "..."
  }
]

Add a machine to a group

curl -X POST http://your-server/api/lists/labcontrol.groups.entities.a1b2c3d4e5f67890abcdef1234567890 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "resourceID": "reflow-oven-01",
      "active": true,
      "expires": false
    }
  }'

Remove a machine from a group

curl -X DELETE http://your-server/api/lists/labcontrol.groups.entities.a1b2c3d4e5f67890abcdef1234567890/ENTITY_UUID \
  -H "Authorization: Bearer $TOKEN"

User group assignments

Group assignments for a user are stored as a nested list at labcontrol.users.groups.{userUUID}. Each entry represents a group membership with optional expiration.

List group assignments

curl http://your-server/api/lists/labcontrol.users.groups.f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN"
[
  {
    "data": {
      "groupID": "a1b2c3d4e5f67890abcdef1234567890",
      "active": true,
      "expires": false,
      "expirationDate": "",
      "creationDate": "2024-01-10T14:00:00.000",
      "type": 0
    },
    "uuid": "..."
  }
]

Assign a group to a user

curl -X POST http://your-server/api/lists/labcontrol.users.groups.f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "groupID": "b2c3d4e5f67890abcdef1234567890a1",
      "active": true,
      "expires": false
    }
  }'

Assign with expiration date

curl -X POST http://your-server/api/lists/labcontrol.users.groups.f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "groupID": "b2c3d4e5f67890abcdef1234567890a1",
      "active": true,
      "expires": true,
      "expirationDate": "2025-03-31T23:59:59.000"
    }
  }'

Deactivate a group assignment

curl -X PATCH http://your-server/api/lists/labcontrol.users.groups.f47ac10b58cc4372a5670e02b2c3d479/MEMBERSHIP_UUID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "active": false
    }
  }'

Remove a group assignment

curl -X DELETE http://your-server/api/lists/labcontrol.users.groups.f47ac10b58cc4372a5670e02b2c3d479/MEMBERSHIP_UUID \
  -H "Authorization: Bearer $TOKEN"

Individual permissions

Permissions for a specific user are stored at labcontrol.users.permissions.{userUUID}. Each entry grants access to a specific resource (machine).

List user permissions

curl http://your-server/api/lists/labcontrol.users.permissions.f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN"
[
  {
    "data": {
      "resourceID": "laser-cutter-01",
      "type": 0,
      "active": true,
      "expires": true,
      "expirationDate": "2025-06-30T23:59:59.000",
      "creationDate": "2024-01-10T14:00:00.000"
    },
    "uuid": "..."
  }
]

Grant a permission

curl -X POST http://your-server/api/lists/labcontrol.users.permissions.f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "resourceID": "cnc-mill-02",
      "active": true,
      "expires": false
    }
  }'

Revoke a permission

curl -X DELETE http://your-server/api/lists/labcontrol.users.permissions.f47ac10b58cc4372a5670e02b2c3d479/PERMISSION_UUID \
  -H "Authorization: Bearer $TOKEN"

User cards

RFID cards assigned to a user are stored at labcontrol.users.cards.{userUUID}:

curl http://your-server/api/lists/labcontrol.users.cards.f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN"

Check if a user has permission

The hasPermission method checks if a user or card has access to a specific resource. It evaluates system groups, custom groups, and individual permissions in one call. Requires LAB_SERVICE permissions.

By user ID:

curl -X POST http://your-server/api/services/lab/hasPermission \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "resourceID": "laser-cutter-01"
  }'

By card ID:

curl -X POST http://your-server/api/services/lab/hasPermission \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cardID": "04:A3:2B:1C:D4:E5:F6",
    "resourceID": "laser-cutter-01"
  }'

7.5 - Working with Logs

Query and create log entries via the REST API.

2log records all machine usage, transactions, and system events as log entries. You can query and filter these logs via the lab service.

Permissions

  • Admins (LAB_ADMIN, LAB_SERVICE, or LAB_SEE_LOGS): can query all logs.
  • Regular users: can only see their own logs. The server automatically adds a userID filter matching the logged-in user.

Querying logs

Use the getLogs service method with a filter object:

curl -X POST http://your-server/api/services/lab/getLogs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "match": {},
      "sort": {"timestamp": -1},
      "limit": 50
    }
  }'

The filter object

Field Type Description
match object MongoDB-style match criteria (see below)
sort object Sort order, e.g. {"timestamp": -1} for newest first, {"timestamp": 1} for oldest first
from string ISO 8601 datetime – start of time range
to string ISO 8601 datetime – end of time range (defaults to now if omitted)
limit int Maximum number of results (-1 or omit for unlimited)

Match criteria

The match object filters log entries by exact field values:

Field Type Description
userID string Filter by user UUID
resourceID string Filter by machine / resource ID
logType int Filter by event type (see table below)

Log event types

Value Name Description
0 BILL Completed session with billing
1 SWITCH_ON Something was switched on
2 SWITCH_OFF Something was switched off
3 START A machine was started
4 STOP A machine was stopped
5 EVENT General event
6 LOGIN User logged in
7 LOGOUT User logged out
8 WARNING Warning
9 ERROR Error
10 OPEN Something was opened (cabinet, lid)
11 CLOSED Something was closed
12 TRANSFER Balance transfer (top-up or deduction)
13 JOB Job with duration
14 OFFLINE Device went offline

Log entry format

Each log entry in the response contains these fields:

{
  "logID": "60a7b2c3d4e5f67890abcdef",
  "resourceID": "laser-cutter-01",
  "userID": "f47ac10b58cc4372a5670e02b2c3d479",
  "userName": "Max Mustermann",
  "email": "max@fablab.org",
  "cardID": "04:A3:2B:1C:D4:E5:F6",
  "logType": 0,
  "units": 120,
  "price": 600,
  "description": "Laser cutting session",
  "timestamp": "2024-01-15T14:30:00.000",
  "startTime": "2024-01-15T14:00:00.000",
  "endTime": "2024-01-15T14:30:00.000",
  "executive": "admin-user-uuid",
  "sessionID": "session-uuid",
  "extType": "",
  "extRef": ""
}
Field Type Description
logID string Unique log entry ID
resourceID string Machine or resource that generated this log
userID string UUID of the user involved
userName string Name of the user at the time of the event
email string Current email of the user (joined from user data)
cardID string RFID card used (if applicable)
logType int Event type (see table above)
units int Usage units (interpretation depends on machine)
price int Cost in cents
description string Human-readable description
timestamp string When the log was created
startTime string Start of the session/event
endTime string End of the session/event
executive string UUID of the user/service that triggered the event
sessionID string Session identifier (groups related log entries)
extType string External system type (e.g. 2log-paydesk)
extRef string External reference ID

Examples

Logs for a specific user

Get the 20 most recent logs for a user:

curl -X POST http://your-server/api/services/lab/getLogs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "match": {
        "userID": "f47ac10b58cc4372a5670e02b2c3d479"
      },
      "sort": {"timestamp": -1},
      "limit": 20
    }
  }'

Logs for a specific machine

Get all logs for the laser cutter:

curl -X POST http://your-server/api/services/lab/getLogs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "match": {
        "resourceID": "laser-cutter-01"
      },
      "sort": {"timestamp": -1}
    }
  }'

Logs in a time range

Get all billing events from January 2024:

curl -X POST http://your-server/api/services/lab/getLogs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "match": {
        "logType": 0
      },
      "from": "2024-01-01T00:00:00.000",
      "to": "2024-02-01T00:00:00.000",
      "sort": {"timestamp": -1}
    }
  }'

Combining filters

Get all laser cutter sessions for a specific user in Q1 2024:

curl -X POST http://your-server/api/services/lab/getLogs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "match": {
        "userID": "f47ac10b58cc4372a5670e02b2c3d479",
        "resourceID": "laser-cutter-01"
      },
      "from": "2024-01-01T00:00:00.000",
      "to": "2024-04-01T00:00:00.000",
      "sort": {"timestamp": -1}
    }
  }'

Adding a log entry

To create a log entry programmatically, use the addLog method. Requires LAB_ADMIN or LAB_SERVICE permissions.

curl -X POST http://your-server/api/services/lab/addLog \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "resourceID": "laser-cutter-01",
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "logType": 5,
    "description": "Manual maintenance note",
    "units": 0,
    "price": 0
  }'

The fields in the request body correspond to the log entry fields described above. The timestamp is set automatically to the current time.

7.6 - Service Reference

Complete reference for all available service methods.

Services provide RPC-style function calls. All service calls use POST:

POST /api/services/{serviceName}/{methodName}

The request body is a JSON object with the method parameters. The server waits up to 30 seconds for a response before returning a 504 timeout.

Discovering services

List all registered services and their methods:

curl http://your-server/api/services \
  -H "Authorization: Bearer $TOKEN"

Get info about a specific service:

curl http://your-server/api/services/lab \
  -H "Authorization: Bearer $TOKEN"
{
  "name": "lab",
  "methods": ["addLog", "getLogs", "resetPassword", "addUser", "deleteUser", ...]
}

lab service

The main service for user management, access control and logging.

Method Description Permissions
addUser Create a new user LAB_ADMIN, LAB_MODIFY_USERS
addOrUpdateUser Create or update a user LAB_ADMIN, LAB_MODIFY_USERS
deleteUser Delete a user LAB_ADMIN, LAB_MODIFY_USERS
resetPassword Send a temporary password by email (any valid token)
transferMoney Add/deduct credit LAB_ADMIN, LAB_SERVICE
getUserForCard Look up user by RFID card LAB_ADMIN, LAB_SERVICE, LAB_SEE_USERS
getUserForExternalReference Look up user by external ID LAB_ADMIN, LAB_SERVICE, LAB_SEE_USERS
hasPermission Check access to a resource LAB_SERVICE
getLogs Query log entries LAB_ADMIN, LAB_SERVICE, LAB_SEE_LOGS (or own logs)
addLog Create a log entry LAB_ADMIN, LAB_SERVICE
addGroup Create a new group LAB_ADMIN, LAB_SERVICE, LAB_MODIFY_GROUPS
getAccumulatedCostsForUser Get total costs for a user in a date range LAB_ADMIN, LAB_SERVICE, LAB_SEE_LOGS (or own costs)
addSystemUser Create a system/admin user LAB_ADMIN, IS_ADMIN, LAB_SERVICE
changeUserLevel Change a system user’s role LAB_ADMIN, IS_ADMIN, LAB_SERVICE

See Users, Groups & Permissions, and Logs for detailed examples.

getAccumulatedCostsForUser

Returns the total accumulated costs for a user within a given date range. The server aggregates all log entries matching the user and time range, and returns the summed totalCost.

Unprivileged users (without LAB_ADMIN, LAB_SERVICE, or LAB_SEE_LOGS permission) can only query their own costs — the userID parameter is ignored and automatically set to the authenticated user’s ID.

curl -X POST http://your-server/api/services/lab/getAccumulatedCostsForUser \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "from": "2024-01-01T00:00:00.000",
    "to": "2024-02-01T00:00:00.000"
  }'
Parameter Type Required Description
userID string yes UUID of the user to query costs for
from datetime yes Start of the date range (ISO 8601)
to datetime no End of the date range (ISO 8601). Defaults to current time if omitted

Response:

[
  {
    "totalCost": 4250
  }
]
Field Type Description
totalCost int Sum of all price values (in cents) from matching log entries

addSystemUser

Creates or updates a system-level user (for admin panel access).

curl -X POST http://your-server/api/services/lab/addSystemUser \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "name": "Admin User",
    "eMail": "admin@fablab.org",
    "level": "admin"
  }'
Parameter Type Required Description
userID string yes UUID of the lab user to promote
name string yes Display name
eMail string yes Email address
level string yes Role level (e.g. admin, viewer)

changeUserLevel

Changes the system role of an existing system user.

curl -X POST http://your-server/api/services/lab/changeUserLevel \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "level": "viewer"
  }'

payment service

Handles point-of-sale billing operations (used by the 2log PayDesk).

Method Description Permissions
preparebill Validate a shopping cart and calculate totals (any valid token)
bill Execute a bill (deduct balance, create logs) IS_ADMIN, LAB_ADMIN, LAB_SEND_BILLS
getsales Get product sales history for a date range (any valid token)

preparebill

Validates a shopping cart, resolves the user, and calculates totals per accounting code. Does not deduct money.

curl -X POST http://your-server/api/services/payment/preparebill \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cardID": "04:A3:2B:1C:D4:E5:F6",
    "bill": [
      {"name": "Laser time 30min", "price": 500, "accountingCode": "laser"},
      {"name": "Material fee", "price": 200, "accountingCode": "material"}
    ],
    "total": 700
  }'
Parameter Type Required Description
cardID string one of cardID/userID RFID card to identify the user
userID string one of cardID/userID User UUID (alternative to cardID)
bill array yes List of items, each with name, price (cents), accountingCode
total int yes Expected total in cents

Response:

{
  "errcode": 0,
  "errstring": "",
  "userID": "f47ac10b...",
  "name": "Max",
  "surname": "Mustermann",
  "eMail": "max@fablab.org",
  "total": 700,
  "discountTotal": 700,
  "bills": [
    {
      "accountingCode": "laser",
      "totalBrutto": 500,
      "totalNetto": 500,
      "discountPercent": 0,
      "items": [...]
    }
  ]
}

bill

Executes the billing: deducts the amount from the user’s balance, creates log entries, and sends a payment confirmation email.

curl -X POST http://your-server/api/services/payment/bill \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cardID": "04:A3:2B:1C:D4:E5:F6",
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "bills": [
      {
        "accountingCode": "laser",
        "totalNetto": 500,
        "items": [
          {"uuid": "item-1", "name": "Laser time 30min", "price": 500, "newprice": 500, "flat": false}
        ]
      }
    ],
    "total": 500,
    "discountTotal": 500
  }'
Parameter Type Required Description
cardID string one of cardID/userID RFID card ID
userID string one of cardID/userID User UUID
bills array yes Array of bill groups (from preparebill response)
total int yes Original total in cents
discountTotal int yes Final total after discounts in cents
cartID string no Unique cart ID (prevents double billing)

Error codes:

errcode Description
0 Success
-2 Unknown user
-3 Invalid parameters
-4 Cart already paid (duplicate cartID)
-5 Credit limit exceeded

getsales

Returns product sales history for a given date range.

curl -X POST http://your-server/api/services/payment/getsales \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "2024-01-01T00:00:00.000",
    "to": "2024-02-01T00:00:00.000"
  }'

devices service

Manages IoT device mappings and firmware updates.

Method Description
hookWithShortID Map a device to a resource by its short ID
unhookWithShortID Remove a device mapping by its short ID
getDeviceTypeWithShortID Get the device type for a short ID
getDeviceTypeWithID Get the device type for a UUID
checkForUpdates Check for available firmware updates
startUpdate Start a firmware update

hookWithShortID

Maps a physical device (identified by its short ID printed on the hardware) to a logical resource name.

curl -X POST http://your-server/api/services/devices/hookWithShortID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "shortID": "AB12",
    "mapping": "laser-cutter-01",
    "force": false,
    "expectedType": "switch"
  }'
Parameter Type Required Description
shortID string yes Short ID of the device
mapping string yes Logical resource name to assign
force bool no Overwrite existing mapping (default: false)
expectedType string no Expected device type; fails if mismatch

Error codes in response:

errorcode Description
0 Success
-11 Device not found
-12 Wrong device type

unhookWithShortID

curl -X POST http://your-server/api/services/devices/unhookWithShortID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"shortID": "AB12"}'

getDeviceTypeWithShortID

curl -X POST http://your-server/api/services/devices/getDeviceTypeWithShortID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"shortID": "AB12"}'

Response:

{"deviceType": "switch", "errorcode": 0}

getDeviceTypeWithID

curl -X POST http://your-server/api/services/devices/getDeviceTypeWithID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"uuid": "device-uuid-here"}'

checkForUpdates

curl -X POST http://your-server/api/services/devices/checkForUpdates \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mapping": "laser-cutter-01"}'

startUpdate

curl -X POST http://your-server/api/services/devices/startUpdate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mapping": "laser-cutter-01",
    "url": "https://firmware.example.com/update.bin"
  }'

machineControl service

Handles the association between 2log controllers (Switch, Dot) and machines.

Method Description
hookSwitch Assign a 2log Switch to a machine
hookDot Assign a 2log Dot to a machine

hookSwitch

Links a 2log Switch device to a machine controller.

curl -X POST http://your-server/api/services/machineControl/hookSwitch \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "shortID": "AB12",
    "deviceID": "machine-controller-id",
    "force": false
  }'
Parameter Type Required Description
shortID string yes Short ID of the Switch device
deviceID string yes ID of the machine controller to attach to
force bool no Overwrite existing assignment

hookDot

Links a 2log Dot device to a machine controller.

curl -X POST http://your-server/api/services/machineControl/hookDot \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "shortID": "CD34",
    "deviceID": "machine-controller-id",
    "force": false
  }'

resources service

Manages 2log resource controllers (the logical representations of machines).

Method Description
newController Create a new resource controller
deleteController Delete a resource controller

newController

curl -X POST http://your-server/api/services/resources/newController \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Laser Cutter",
    "type": "machines",
    "uid": "laser-cutter-01"
  }'
Parameter Type Required Description
name string yes Display name
type string yes Resource type (e.g. machines, suctions)
uid string yes Unique device/resource ID

Response:

{"success": true, "data": {...}}

deleteController

curl -X POST http://your-server/api/services/resources/deleteController \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"uid": "laser-cutter-01"}'

codeAuthenticator service

Handles QR-code based authentication (used by the 2log mobile app).

Method Description
authenticate Authenticate a session via a temporary code

authenticate

The 2log app displays a QR code containing a temporary code. When scanned (e.g. by a terminal), this method is called to authenticate the session.

curl -X POST http://your-server/api/services/codeAuthenticator/authenticate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"code": "https://2log.app/AB3F7K9X"}'
Parameter Type Required Description
code string yes The temporary authentication code

Response:

{"errcode": 0}

errcode -1 means the code is unknown or expired.

7.7 - Error Handling

HTTP status codes and error response format.

Error response format

All error responses follow a consistent JSON format:

{"error": true, "code": 403, "message": "Invalid token. Please log in and try again."}

HTTP status codes

Code Meaning
200 Success
201 Created (file upload)
400 Invalid request data, missing parameters, or malformed JSON
401 Authentication failed (wrong password, unknown user)
403 Invalid token or insufficient permissions
404 Resource, item, property, service, or method not found
405 HTTP method not supported for this endpoint
500 Internal server error (e.g. resource could not be accessed)
502 Service call returned invalid data
504 Service call timed out (30 second limit)

Common error messages

Message Cause
Missing credentials Login request without user or pass
Invalid token. Please log in and try again. Token expired or invalid
Permission denied Authenticated but lacking the required permission
Missing 'data' field POST/PUT/PATCH without data in body
Missing item identifier PUT/PATCH/DELETE on a list without specifying an ID
Item not found / Property not found ID or property does not exist
Service not found Unknown service name
Unknown method Service exists but method name is wrong
Service call timed out Service did not respond within 30 seconds

8 - Selling Products

Here you will learn how you can sell products with 2log.io

Members can also use their 2log account to pay for products. For this purpose, there is the so-called “tally sheet”, which implements a simple payment system in the form of a self-service terminal.

Whether drinks, snacks or materials. It is up to you which products you offer. With the simple product management you keep the prices always up to date and have an exact overview of what was sold in which period.



8.1 - Manage Products and Prices

Learn how to add products and manage prices

2log offers a simple product management. With it you can add products, group them into categories, manage prices and assign booking codes. Log in to the 2log Admin Portal and click on the “Products” tab.

The mysterious Checkbox

The checkbox activates the corresponding product for the tally list. This can be used to hide products that are temporarily unavailable.

Category

The product category is only a logical grouping to increase the clarity, so that the desired product is found faster. In the tally list, a separate tab is displayed for each category. The category has no influence on the billing.

Accounting Code

The booking code is taken into account in the statistics and is used to distribute the revenue to different positions.

8.2 - The 2log.io Tally Sheet

Here you will learn how to set up the 2log tally sheet

The 2log tally sheet is a graphical interface for billing all kinds of products in the style of a self service vending machine. The products offered can be managed centrally via the 2log.io user interface. The products can be paid either with the 2log card or the 2log App by scanning a QR code.

Prepare the Device

The 2log tally sheet runs on all major platforms, if you compile it yourself. Especially single board computers like the Raspberry Pi are a good choice. The easiest way to set up the 2log tally sheet is on a 7" or 10" Android tablet.

Android

This is by far the easiest way to set up the tally sheet: Just download the APK from here and install it on your tablet.

RaspberryPi

A Raspberry Pi Zero is perfectly sufficient. In the Gitlab repository there are DXF milling files for a nice case. For compiling the sources for the raspberry pi, you can use the docker based cross toolchains.

Pair the Device

  1. The first time you start the app, you must enter the host address of the 2log server.
  2. Log in to the 2log.io admin interface. Switch to the “Administration” tab and open the “Device Explorer” via the button in the top right corner.
  3. The device should now appear under “new devices”. Click on the “+” and assign an address to the device.

Configuration

The SelfService Terminal can be configured via the DeviceExplorer. Depending on the resolution and screen diagonal, it may make sense to set parameters such as the size of the tiles or the font size. Make sure you have added a few products so you can better judge the appearance.

Visual Appearence

You can access the settings via the Device Explorer in the administration area. Just click on the terminal and change the parameters labelFontSize, maxCellWidth and priceFontSize. After clicking on “Send”, the changes are directly transferred to the device and are immediately visible.

Assign a Dot

In order for users to be able to pay with their RFID card later, you need a 2log Dot. The Dot can be assigned to the tally sheet via the 2log admin interface.