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

Return to the regular view of this page

As of 2025-07-24

TWELITE WINGS API / MWings

A library for use on devices connected to the TWELITE parent device
MWings is a library for use on devices connected to a TWELITE programmed with the Parent and Repeater App (App_Wings). It interprets the format strings output by App_Wings and provides to the host device the data received by the parent device. It can also construct commands for App_Wings to control child devices.

1 - TWELITE Wings API / MWings for Python

TWELITE Wings API / MWings for Python

1.1 - TWELITE Wings API / MWings for Python

Latest Edition
By using the TWELITE Wings API (MWings), you can control TWELITE from Python scripts on your PC.

Library Overview

The TWELITE Wings API (hereafter MWings) is a library for handling TWELITE from Python scripts.

Features

You can communicate with TWELITE child nodes through a TWELITE parent node connected to the host.

  • Interpret received data and convert it to a dictionary, JSON, or pandas DataFrame*
  • Send commands generated from dictionaries to the parent node
  • The Lite version does not support pandas.

Example Use Cases

For example, you can implement systems like the following:

  • Send temperature and humidity data received by MONOSTICK to a cloud server as JSON
  • Record acceleration data received by MONOSTICK to a CSV or Excel file*
  • Control an LED connected to TWELITE DIP via MONOSTICK from a PC
  • The Lite version cannot output directly to CSV or Excel files.

Characteristics

This is a module for modern Python, by modern Python, for modern Python.

  • With exceptions. Details explained later.

Installation

Available from PyPI.

pip の場合


pip install mwings

poetry の場合


poetry add mwings

The Simplest Sample Script

In just 6 lines, you can output received data from the Extremely Simple! Standard App (App_Twelite) in JSON format.

import mwings as mw
twelite = mw.Twelite(mw.utils.ask_user_for_port())
@twelite.on(mw.common.PacketType.APP_TWELITE)
def on_app_twelite(packet):
    print(packet.to_json())
twelite.start()

Environment Setup and Operation Check

What You Need

  • PC
  • MONOSTICK (Parent and Repeater App / default settings)
  • TWELITE DIP (Extremely Simple! Standard App / default settings)
    • Connect peripherals such as switches (example: connect a tact switch between DI1 port and GND)

Environment Setup

Installing pyenv

To manage the Python interpreter version, install pyenv.

Linux

curl https://pyenv.run | bash
macOS

brew update
brew install pyenv
Windows

There is no pyenv for Windows. Instead, use pyenv-win.

Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"

Installing Python with pyenv / pyenv-win

Install Python 3.12 or later (3.11 or later for Lite version), as required by MWings.

To list available versions, run:

pyenv install -l

For example, to install Python 3.12.4 and apply it system-wide:

pyenv install 3.12.4
pyenv global 3.12.4

To list installed versions, run:

pyenv versions

Installing pipx

To manage command-line tools such as poetry in an isolated environment, install pipx.

Linux

Debian-based


sudo apt update
sudo apt install pipx
pipx ensurepath

From pip (recommended for Raspberry Pi)


python3 -m pip install --user pipx
python3 -m pipx ensurepath

Fedora-based


sudo dnf install pipx
pipx ensurepath

Reference: Installation - pipx

macOS

brew install pipx
pipx ensurepath
Windows
scoop install pipx
pipx ensurepath

Installing poetry

To manage the Python interpreter version and module dependencies for your project (similar to Node.js), install poetry.

pipx install poetry

Creating a Project

Here, we will use mwtest as the project name.

Move to the directory where you want to create the project and run:

poetry new mwtest

This will generate the mwtest directory.

Project Setup

Move into the project directory and link it to the Python version you installed earlier with pyenv.

poetry env use 3.12.4

Install MWings.

poetry add mwings

Creating the Simplest Sample Script

First, let’s try running the script introduced earlier.

import mwings as mw
twelite = mw.Twelite(mw.utils.ask_user_for_port())
@twelite.on(mw.common.PacketType.APP_TWELITE)
def on_app_twelite(packet):
    print(packet.to_json())
twelite.start()

上記の内容で poetry が生成した __init__.py と同じ階層に simple.py を作成します。

📁 mwtest
└ 📁 mwtest
  ├ 📄 __init__.py
  └ 📄 simple.py

Running the Simplest Sample Script

Connect MONOSTICK and run:

poetry run python simple.py

If there are multiple serial ports, please select the serial port.

If you get output in JSON string format, you have succeeded. An example of actual output is shown below.

{
  "time_parsed": "2024-02-20T03:16:50.150386+00:00",
  "packet_type": "APP_TWELITE",
  "sequence_number": 13699,
  "source_serial_id": "810E0E23",
  "source_logical_id": 120,
  "lqi": 84,
  "supply_voltage": 3249,
  "destination_logical_id": 0,
  "relay_count": 0,
  "periodic": true,
  "di_changed": [
    true,
    true,
    false,
    false
  ],
  "di_state": [
    false,
    false,
    false,
    false
  ],
  "ai_voltage": [
    8,
    272,
    1032,
    112
  ],
  "mwings_implementation": "python",
  "mwings_version": "1.0.0",
  "hostname": "silverstone.local",
  "system_type": "Darwin"
}

Creating a Practical Script

simple.py is just an explanatory sample. It is not a practical script.

This is because twelite.start() creates a thread to receive data, but does not provide a way to terminate it. It is also a very hard-to-read script.

Next, let’s create a more practical script. After running it, we will explain its contents.

This time, we will set the following three conditions:

Below is an example applying these points.

# -*- coding:utf-8 -*-
# Written for Python 3.12
# Formatted with Black

# MWings example: Receive data, print JSON, typed

from zoneinfo import ZoneInfo

import mwings as mw


# Main function
def main() -> None:
    # Create a twelite object
    twelite = mw.Twelite(mw.utils.ask_user_for_port())

    # Use JST for received data
    twelite.set_timezone(ZoneInfo("Asia/Tokyo"))

    # Register an event handler
    @twelite.on(mw.common.PacketType.APP_TWELITE)
    def on_app_twelite(packet: mw.parsers.app_twelite.ParsedPacket) -> None:
        print(packet.to_json(verbose=True, spread=False))

    # Start receiving
    try:
        # Set as daemon thread
        twelite.daemon = True
        # Start the thread, Join to the main thread
        twelite.start()
        print("Started receiving")
        while True:
            twelite.join(0.5)
    except KeyboardInterrupt:
        # Stop the thread
        print("Flushing...")
        twelite.stop()
        print("Completed")


if __name__ == "__main__":
    # Call the main function
    main()

Please save the above as practical.py.

📁 mwtest
└ 📁 mwtest
  ├ 📄 __init__.py
  ├ 📄 simple.py
  └ 📄 practical.py

Running the Practical Script

Run the following command to get output in JSON format, just like with simple.py.

poetry run python practical.py

However, this time you can exit with Ctrl+C without causing an error, and time_parsed should be in Japan Standard Time.

Explanation of the Practical Script

Code Explanation

Let’s explain practical.py.

import Statements

In practical.py, two modules are imported:

from zoneinfo import ZoneInfo

import mwings as mw
  • zoneinfo.ZoneInfo is used to specify the time zone for the received timestamp.
  • mwings is the MWings library. It is imported as mw for brevity. For the Lite version, use mwingslite.
Creating the Object

The mw.Twelite object serves as the interface to access the TWELITE parent node connected to the host.

    # Create a twelite object
    twelite = mw.Twelite(mw.utils.ask_user_for_port())

The mw.utils.ask_user_for_port() function gets a list of available serial ports on the host and returns the file descriptor path or COM port name selected by the user.

Setting the Time Zone

By default, the reception time of data is treated as UTC.

In practical.py, this is set to JST.

    # Use JST for received data
    twelite.set_timezone(ZoneInfo("Asia/Tokyo"))

Pass an IANA time zone identifier to ZoneInfo.

Registering a Receive Handler

To process data sent from TWELITE child nodes, register a receive handler. Here, in the receive handler for the Extremely Simple! Standard App, the received data is converted to JSON format and output.

    # Register an event handler
    @twelite.on(mw.common.PacketType.APP_TWELITE)
    def on_app_twelite(packet: mw.parsers.app_twelite.ParsedPacket) -> None:
        print(packet.to_json(verbose=True, spread=False))

You can register a receive handler by applying the twelite.on() decorator ? to any function.

The data class ParsedPacket received by the handler has methods such as to_json() to convert to a JSON string, to_dict() to convert to a dictionary, and to_df() to convert to a pandas DataFrame.

Here, the to_json() method is used to convert to a JSON string.

        print(packet.to_json(verbose=True, spread=False))
Starting and Stopping Reception

mw.Twelite inherits from threading.Thread. In practical.py, twelite.start() starts the receive process in a separate thread, and twelite.stop() stops it.

    # Start receiving
    try:
        # Set as daemon thread
        twelite.daemon = True
        # Start the thread, Join to the main thread
        twelite.start()
        print("Started receiving")
        while True:
            twelite.join(0.5)
    except KeyboardInterrupt:
        # Stop the thread
        print("Flushing...")
        twelite.stop()
        print("Completed")

Setting twelite.daemon to True makes the receiving subthread a daemon. When all non-daemon threads have exited, the whole Python program will also exit. Here, the main thread is kept waiting by repeatedly calling twelite.join().

When the main thread detects Ctrl+C input, it calls twelite.stop() in the except block to stop the receive process. twelite.stop() waits until the subthread finishes calling the receive handler.

Supplementary Explanation

PEP8 Compliance

practical.py and the MWings source code are formatted using the Black code formatter, which is compatible with PEP8.

Except for the maximum line length, Black does not accept any configuration, making it a stubborn formatter, but it saves the trouble of formulating and sharing coding standards. Coding rules are often contentious, but spending resources on such trivial matters rather than on productive work goes against the Python spirit.

To add Black to your project, run:

poetry add --group dev black

You can run it on specific files or directories:

poetry run black mwtest

You can also check without formatting:

poetry run black --check mwtest
Type Hint Support

practical.py and the MWings source code support type hints.

The MWings library uses mypy, the official static type checker for Python.

To add mypy to your project, run:

poetry add --group dev mypy

Like Black, you can specify files or directories to check:

poetry run mypy mwtest

Practical Script Applications

We provide scripts that further develop practical.py.

mwings_python/examples at main

log_export.py

Reads a text file containing output from the parent node, interprets it, saves the results as a pandas DataFrame, and finally outputs to a CSV or Excel file. Not supported in the Lite version.

rx_export.py

Receives output from the connected parent node, interprets the results, saves them as a pandas DataFrame, and finally outputs to a CSV or Excel file. Not supported in the Lite version.

  • If you select a CSV file, all results are saved in a single file.
  • If you select an Excel file instead, the results are saved in separate sheets by packet type.

rx_export_csv_durable.py

Receives output from the connected parent node, interprets the results, and appends them to CSV files by source serial ID. Not supported in the Lite version.

rx_print_df.py

Receives output from the connected parent node, simply converts the interpreted results to a pandas DataFrame, and outputs them as a string. Not supported in the Lite version.

rx_print_dict.py

Receives output from the connected parent node, simply converts the interpreted results to a dictionary, and outputs them. Also supported in the Lite version.

rx_print_json.py

Receives output from the connected parent node, simply converts the interpreted results to a JSON string, and outputs them. Also supported in the Lite version.

tx_binary_uart.py

Sends binary data [0xBE, 0xEF] to TWELITE UART via the connected parent node running the Serial Communication App. Also supported in the Lite version.

Blinks the LED connected to the DO1 port of TWELITE DIP via the connected Parent and Repeater App parent node. Also supported in the Lite version.

Turns on the LED of the Notification PAL in each color via the connected Parent and Repeater App parent node. Also supported in the Lite version.

API Reference

2 - TWELITE Wings API / MWings for 32-bit Arduinos

TWELITE Wings API / MWings for 32-bit Arduino boards

2.1 - TWELITE Wings API / MWings for 32-bit Arduinos

Latest Edition

2.1.1 - Using with TWELITE SPOT

How to use with the ESP32 on TWELITE SPOT
TWELITE SPOT Start Guide: See Receiving Data from TWELITE Child Devices.

2.1.2 - Using with Arduino UNO R4

How to use with the Arduino UNO R4 series
This guide explains how to connect TWELITE parent devices such as TWELITE UART or TWELITE DIP to the Arduino UNO R4 series and communicate with child devices using the MWings library.

Hardware Preparation

Preparing TWELITE

Write the Parent and Repeater App (App_Wings) to products such as TWELITE UART and TWELITE DIP.

Use the TWELITE STAGE APP for writing.

Connection with Arduino UNO R4

Use the following TWELITE pins:

  • VCC (connect to 3.3V)
  • GND (connect to GND)
  • TXD (connect to D0/RX)
  • RXD (connect to D1/TX)
  • RST (connect to any port such as D11)
  • PRG (connect to any port such as D12)

Below is an example wiring diagram based on the sample sketch included with the library.

Example connection with Arduino

Example connection with Arduino

Software Preparation

Installing the Library

You can install it via the Arduino Library Manager.

Refer to the TWELITE SPOT manual: Installing the MWings Library.

Verifying the Sample Sketch Operation

The library includes simple sample sketches for communicating with each TWELITE device.

For example, to receive data from the Extremely Simple! Standard App (App_Twelite), open the following sample sketch from the menu bar:

File > Examples > MWings > Arduino UNO R4 > Receive > monitor_uno_r4_app_twelite
Example display

Example display

monitor_uno_r4_app_twelite.ino

// Monitor example for TWELITE with Arduino UNO R4: Receive data from App_Twelite

#include <Arduino.h>
#include "MWings.h"

const int RST_PIN = D11;
const int PRG_PIN = D12;
const int LED_PIN = D13;        // Use on-board LED as indicator

const uint8_t TWE_CHANNEL = 18;
const uint32_t TWE_APP_ID = 0x67720102;

void setup()
{
    // Initialize serial ports
    while (!Serial && millis() < 5000); // Wait for internal USB-UART
    Serial.begin(115200);
    Serial.println("Monitor example for TWELITE with Arduino UNO R4: App_Twelite");
    Serial1.begin(115200);

    // Initialize TWELITE
    if (Twelite.begin(Serial1,
                      LED_PIN, RST_PIN, PRG_PIN,
                      TWE_CHANNEL, TWE_APP_ID)) {
        Serial.println("Successfully initialized TWELITE");
    } else {
        Serial.println("Failed to initialize TWELITE");
    }

    // Attach an event handler to process packets from App_Twelite
    Twelite.on([](const ParsedAppTwelitePacket& packet) {
        Serial.println("");
        Serial.print("Packet Timestamp:  ");
        Serial.print(packet.u16SequenceNumber / 64.0f, 1); Serial.println(" sec");
        Serial.print("Source Logical ID: 0x");
        Serial.println(packet.u8SourceLogicalId, HEX);
        Serial.print("LQI:               ");
        Serial.println(packet.u8Lqi, DEC);
        Serial.print("Supply Voltage:    ");
        Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV");
        Serial.print("Digital Input:    ");
        Serial.print(packet.bDiState[0] ? " DI1:Lo" : " DI1:Hi");
        Serial.print(packet.bDiState[1] ? " DI2:Lo" : " DI2:Hi");
        Serial.print(packet.bDiState[2] ? " DI3:Lo" : " DI3:Hi");
        Serial.println(packet.bDiState[3] ? " DI4:Lo" : " DI4:Hi");
        Serial.print("Analog Input:     ");
        Serial.print(" AI1:"); Serial.print(packet.u16AiVoltage[0]); Serial.print(" mV");
        Serial.print(" AI2:"); Serial.print(packet.u16AiVoltage[1]); Serial.print(" mV");
        Serial.print(" AI3:"); Serial.print(packet.u16AiVoltage[2]); Serial.print(" mV");
        Serial.print(" AI4:"); Serial.print(packet.u16AiVoltage[3]); Serial.println(" mV");
    });
}

void loop()
{
    // Update TWELITE
    Twelite.update();
}

/*
 * Copyright (C) 2023 Mono Wireless Inc. All Rights Reserved.
 * Released under MW-OSSLA-1J,1E (MONO WIRELESS OPEN SOURCE SOFTWARE LICENSE AGREEMENT).
 */

The following are specific to Arduino UNO R4.

Port Settings

Lines 6-8 configure Arduino ports excluding UART-related pins.

const int RST_PIN = D11;
const int PRG_PIN = D12;
const int LED_PIN = D13;        // Use on-board LED as indicator
PinRoleNotes
D11TWELITE RST controlSee the connection example above
D12TWELITE PRG controlSee the connection example above
D13Communication indicator LED controlUses built-in LED

Waiting for USB Serial Port Initialization

Line 16 waits for the USB serial port (Serial) to initialize.

    while (!Serial && millis() < 5000); // Wait for internal USB-UART

Arduino UNO R4 does not have a USB-serial converter IC like UNO R3; the ARM CPU itself handles USB serial conversion. Therefore, communication cannot occur before the serial port initialization completes.

2.1.3 - Extending Packet Parsers

How to add packet parsers
In the MWings library, you can easily add packet parsers.

Overview

To add a parser, you need to edit the following four files:

  • (New) Parser header file parser/FooBarPacketParser.h
    • Write the contents of the packet to be parsed and the criteria for a valid packet
  • (New) Parser source file parser/FooBarPacketParser.cpp
    • Write the part that interprets the packet contents
  • (Append) Main header file MWings.h
    • Add the parser
  • (Append) Main source file MWings.cpp
    • Add the parser

Parser Header File

Duplicate an existing file under parser/ and rename it.

Here, we create parser/AppTagAdcPacketParser.h.

#ifndef APPTAGADCPACKETPARSER_H
#define APPTAGADCPACKETPARSER_H

#include "MWings_Common.h"

/**
 * @struct ParsedAppTagAdcPacket
 * @brief  Packet content for App_Tag (ADC)
 */
struct ParsedAppTagAdcPacket final : public mwings::ParsedPacketBase {
    uint32_t u32RouterSerialId;
    uint8_t u8SensorType;
    uint16_t u16AiVoltage[2];
};

/**
 * @class apptagadc::PacketParser
 * @brief  Packet parser for App_Tag (ADC)
 */
namespace apptagadc {
class PacketParser final : public mwings::PacketParserBase {
public:
    // Check if the packet is from App_Tag (ADC)
    inline bool isValid(const BarePacket& barePacket) const override {
        if ((barePacket.u8At(12) == 0x10)
            and (barePacket.u32At(18) == 0)
            and (barePacket.u16PayloadSize == 22)) {
            return true;
        }
        return false;
    }

    // Parse from bare packet
    bool parse(const BarePacket& barePacket, mwings::ParsedPacketBase* const parsedPacket) const override;
};
}

extern apptagadc::PacketParser AppTagAdcPacketParser;

#endif  // APPTAGADCPACKETPARSER_H

Describing the Packet Contents to be Parsed

First, please check the App_Tag (Analog Sensor) output format.

After replacing the include guard, namespace, and comments, inherit from mwings::ParsedPacketBase and describe the packet contents.

Here, declare data unique to the target device. General data such as the destination logical device ID is already registered in mwings::ParsedPacketBase.

In the following section, unique data for App_Tag (Analog Sensor) is declared.

struct ParsedAppTagAdcPacket final : public mwings::ParsedPacketBase {
    uint32_t u32RouterSerialId;
    uint8_t u8SensorType;
    uint16_t u16AiVoltage[2];
};

Writing the Criteria for a Valid Packet

Create apptagadc::PacketParser inheriting from mwings::PacketParserBase and override the pure virtual function isValid() to specify the criteria for a valid packet.

Packets matching this condition will be parsed.

In the following, it checks that the sensor type is 0x10 (analog sensor), the unused area is 0, and the payload length is 22 bytes.

inline bool isValid(const BarePacket& barePacket) const override {
    if ((barePacket.u8At(12) == 0x10)
        and (barePacket.u32At(18) == 0)
        and (barePacket.u16PayloadSize == 22)) {
        return true;
    }
    return false;
}

Parser Source File

Duplicate an existing file under parser/ and rename it.

Here, we create parser/AppTagAdcPacketParser.cpp.

#include "AppTagAdcPacketParser.h"

apptagadc::PacketParser AppTagAdcPacketParser;

bool apptagadc::PacketParser::parse(const BarePacket& barePacket, mwings::ParsedPacketBase* const parsedPacket) const
{
    // WARNING: Note that there is NO RTTI
    ParsedAppTagAdcPacket* const parsedAppTagAdcPacket = static_cast<ParsedAppTagAdcPacket*>(parsedPacket);

    parsedAppTagAdcPacket->u32SourceSerialId = barePacket.u32At(7);
    parsedAppTagAdcPacket->u8SourceLogicalId = barePacket.u8At(11);
    parsedAppTagAdcPacket->u16SequenceNumber = barePacket.u16At(5);
    parsedAppTagAdcPacket->u8Lqi = barePacket.u8At(4);

    const uint16_t ecc = barePacket.u8At(13);
    if (ecc <= 170) {
        parsedAppTagAdcPacket->u16SupplyVoltage = 5 * ecc + 1950;
    } else {
        parsedAppTagAdcPacket->u16SupplyVoltage = 10 * (ecc - 170) + 2800;
    }

    parsedAppTagAdcPacket->u32RouterSerialId = barePacket.u32At(0);
    parsedAppTagAdcPacket->u8SensorType = barePacket.u8At(12);

    for (int i = 0; i < 2; i++) {
        parsedAppTagAdcPacket->u16AiVoltage[i] = barePacket.u16At(2*i+14);
    }

    return true;
}

Writing the Parsing Logic

After replacing the header file name and namespace, write the contents of parse().

The following stores the packet contents according to the data format.

Use methods like BarePacket.u8At() to extract data from the raw payload.

// WARNING: Note that there is NO RTTI
ParsedAppTagAdcPacket* const parsedAppTagAdcPacket = static_cast<ParsedAppTagAdcPacket*>(parsedPacket);

parsedAppTagAdcPacket->u32SourceSerialId = barePacket.u32At(7);
parsedAppTagAdcPacket->u8SourceLogicalId = barePacket.u8At(11);
parsedAppTagAdcPacket->u16SequenceNumber = barePacket.u16At(5);
parsedAppTagAdcPacket->u8Lqi = barePacket.u8At(4);

const uint16_t ecc = barePacket.u8At(13);
if (ecc <= 170) {
    parsedAppTagAdcPacket->u16SupplyVoltage = 5 * ecc + 1950;
} else {
    parsedAppTagAdcPacket->u16SupplyVoltage = 10 * (ecc - 170) + 2800;
}

parsedAppTagAdcPacket->u32RouterSerialId = barePacket.u32At(0);
parsedAppTagAdcPacket->u8SensorType = barePacket.u8At(12);

for (int i = 0; i < 2; i++) {
    parsedAppTagAdcPacket->u16AiVoltage[i] = barePacket.u16At(2*i+14);
}

Main Header File

In addition to existing parsers, add the new parser.

Adding Include Directive

Include the packet parser header file.

//// AppTagAdcPacketParser for App_Tag (ADC)
#include "parser/AppTagAdcPacketParser.h"

Extending the Initializer List

Initialize the event handler to nullptr.

               //// AppTagAdcPacketParser for App_Tag (ADC)
               _onAppTagAdcPacket(nullptr),

Adding Cleanup Code

Reset the event handler to nullptr.

//// AppTagAdcPacketParser for App_Tag (ADC)
_onAppTagAdcPacket = nullptr;

Adding Event Handler Registration Method

Add an on() method to register the event handler.

//// AppTagAdcPacketParser for App_Tag (ADC)
inline void on(void (*callback)(const ParsedAppTagAdcPacket& packet)) { _onAppTagAdcPacket = callback; }

Adding Event Handler Member

Add a pointer to store the event handler.

//// AppTagAdcPacketParser for App_Tag (ADC)
void (*_onAppTagAdcPacket)(const ParsedAppTagAdcPacket& packet);

Editing Main Source File

Add the new parsing process in addition to the existing parsing.

Initializing the Event Handler

Ensure the event handler is initialized when begin() is called.

//// AppTagAdcPacketParser for App_Tag (ADC)
_onAppTagAdcPacket = nullptr;

Adding Parsing Process

Parse the target packet when received.

//// Start: AppTagAdcPacketParser for App_Tag (ADC)
if (AppTagAdcPacketParser.isValid(barePacket) and _onAppTagAdcPacket) {
    ParsedAppTagAdcPacket parsedAppTagAdcPacket;
    if (AppTagAdcPacketParser.parse(barePacket, &parsedAppTagAdcPacket)) {
        _onAppTagAdcPacket(parsedAppTagAdcPacket);
    }
}
//// End: AppTagAdcPacketParser for App_Tag (ADC)

Applying Changes

When you build the sketch, the library will also be rebuilt.