Skip to content

Repository files navigation

OpenSmell

An open interoperability layer for digital olfaction.

Tests Python License Status

OpenSmell provides a device-independent way to represent, exchange, validate, and request the rendering of digital olfactory information across software, data sources, scientific models, and heterogeneous devices.

OpenSmell interoperability architecture

OpenSmell does not define how an odor must physically be reproduced. It provides an interoperability layer between systems that produce, store, transform, interpret, or render olfactory information.

The interoperability problem

Digital olfaction already spans odor datasets, chemical information, machine- learning models, electronic noses, research software, and scent-display hardware. These systems may use different representations, vocabularies, data models, and device interfaces. OpenSmell explores a common layer that lets them exchange olfactory information without requiring one universal physical smell reproduction technology.

Dataset A ─┐
Model B   ─┼──► different representations ──► OpenSmell ──► applications / devices
Sensor C  ─┘

30-second example

An .osmell document can carry multiple representations of the same conceptual odor. Applications use the representations they understand and preserve the ones they do not.

import opensmell

odor = opensmell.load("examples/coffee.osmell")

print(odor.id)
print(odor.metadata.labels.get("en"))
for representation in odor.representations:
    print(representation.type, representation.scheme.id)

OpenSmell can therefore transport semantic, perceptual, chemical, mixture, or future representations while keeping physical rendering decisions outside the Core format.

Current implementation at a glance

Area Status
OpenSmell Core 0.1 format and JSON Schema Implemented
Python reference implementation Implemented
Forward-compatible schemes and extension preservation Implemented
Experimental ResourceGraph interoperability Implemented and tested
Portable Python/JavaScript interoperability vectors Implemented
Experimental rendering and device architecture Documented through RFC-0012
Device Protocol 0.1 and serial transport Implemented experimentally
Automated Python test suite More than 1,700 tests passing in the latest audited local run
Physical hardware validation ESP32/LED control path validated experimentally

Important

OpenSmell is an early-stage experimental project. Version 0.1 is pre-alpha and must not be treated as a stable standard. Experimental graph, rendering, device, and protocol APIs may change.

What OpenSmell is — and is not

OpenSmell is an interoperability framework. It is not an electronic nose, a chemical analysis platform, an odor-prediction model, a physical scent diffuser, or a claim that arbitrary smells can already be perfectly digitized and reproduced. Those technologies may produce or consume information through OpenSmell, but they remain separate systems.

Explore the project


Why OpenSmell?

Digital olfaction is an emerging field involving technologies such as:

  • electronic noses and chemical sensors;
  • machine-learning models for odor perception;
  • digital odor databases;
  • scent displays and olfactory interfaces;
  • VR/AR olfactory experiences;
  • remote odor reproduction;
  • odor digitization research. Several projects and standards already address parts of this ecosystem. However, these systems may represent odors differently and may rely on different hardware, models, vocabularies, measurement protocols, or delivery technologies. OpenSmell explores a simple question:

Can digital odor information be represented and exchanged independently from the technology that eventually interprets or renders it? The project aims to investigate and implement this interoperability layer.


Core principle

OpenSmell must not assume how an odor is physically reproduced. A future olfactory display might use:

  • a small number of odor primaries;
  • hundreds of chemical cartridges;
  • predefined scent cartridges;
  • dynamically generated mixtures;
  • technologies that do not exist yet. OpenSmell should therefore describe olfactory information without forcing every device to use the same physical reproduction mechanism. Conceptually:
Scientific data / Models / Sensors
               │
               ▼
       Digital odor information
               │
               ▼
           ┌───────────┐
           │ OpenSmell │
           └───────────┘
               │
        ┌──────┼──────┐
        ▼      ▼      ▼
 Application  Mapper  Storage
               │
               ▼
         Device adapter
               │
               ▼
        Olfactory device

OpenSmell focuses primarily on the interoperability layer, not on the physical diffuser itself.


What OpenSmell 0.1 provides

The current reference implementation includes:

  • a JSON-based .osmell document format;
  • JSON Schema validation;
  • Python data models;
  • .osmell loading and serialization;
  • multiple representations per odor;
  • representation scheme validation;
  • a scheme registry;
  • semantic descriptor representations;
  • chemical SMILES representations;
  • builders for creating OpenSmell objects;
  • forward-compatible handling of unknown schemes;
  • preservation of unknown extension fields;
  • document-level lossless round trips;
  • an experimental OdorNet adapter;
  • experimental semantic annotation modeling based on real OdorNet data;
  • an experimental Keller/Vosshall adapter for quantitative perceptual measurements;
  • optional PubChem chemical identity enrichment;
  • an experimental Geraniol .osmell fixture and deterministic regeneration path from a locally prepared external OdorNet + PubChem enrichment dataset;
  • experimental rendering requests, rendering plans, semantic channel mapping, device capabilities, and device adapters;
  • experimental Device Protocol 0.1 with transport-independent adapters;
  • optional serial transport using PySerial;
  • a physically validated ESP32/LED control-path prototype;
  • experimental deterministic resource identification based on canonical source identity and UUIDs;
  • cross-language Python/JavaScript identifier interoperability tests;
  • an experimental generic resource model with Stimulus, ObservationTarget, Observation, versioned ResultScheme, and scheme-defined Result objects;
  • an experimental flat ResourceGraph with Resource-ID references and unresolved-reference preservation;
  • an experimental JSON ResourceGraph serialization format;
  • dataset-scale ResourceGraph round-trip validation across human psychophysics, biological physiology, and electronic olfaction;
  • automated tests and CI;
  • an RFC-based design process. The current implementation deliberately keeps these experimental graph concepts outside OpenSmell 0.1 Core. OpenSmell 0.1 does not attempt to solve physical odor reproduction.

Representation model

An OpenSmell odor may contain multiple representations of the same conceptual odor. For example:

                         Odor
                          │
             ┌────────────┼────────────┐
             ▼            ▼            ▼
         Semantic     Perceptual    Chemical
             │            │            │
             └────────────┼────────────┘
                          ▼
                      OpenSmell

Different applications can use the representations they understand. OpenSmell 0.1 recognizes the following broad representation type names:

semantic
perceptual
chemical
mixture

These are broad categories only. The actual interpretation of a representation is defined by its scheme. Unknown representation types and unknown schemes are allowed so that OpenSmell can evolve without requiring every implementation to understand every possible representation.


Representation schemes

Every representation identifies a scheme. A scheme defines how the representation's data field should be interpreted. Example:

{
  "type": "semantic",
  "scheme": {
    "id": "org.opensmell.semantic.descriptors",
    "version": "0.1"
  },
  "data": {
    "descriptors": [
      {
        "value": "coffee",
        "language": "en"
      },
      {
        "value": "roasted",
        "language": "en"
      }
    ]
  }
}

Here:

type

identifies the broad representation family.

scheme

defines the specific rules used to interpret the data. This separation allows OpenSmell to transport representations produced by different scientific models, datasets, organizations, and future technologies.


Built-in schemes

org.opensmell.semantic.descriptors

Version:

0.1

Representation type:

semantic

This scheme represents an odor using human-readable semantic descriptors. Example:

{
  "type": "semantic",
  "scheme": {
    "id": "org.opensmell.semantic.descriptors",
    "version": "0.1"
  },
  "data": {
    "descriptors": [
      {
        "value": "coffee",
        "language": "en"
      },
      {
        "value": "roasted",
        "language": "en"
      },
      {
        "value": "bitter",
        "language": "en"
      }
    ]
  }
}

This representation describes an odor. It does not specify how a physical device should reproduce it.

org.opensmell.chemical.smiles

Version:

0.1

Representation type:

chemical

This scheme associates molecular structure information with an OpenSmell odor using SMILES. Example:

{
  "type": "chemical",
  "scheme": {
    "id": "org.opensmell.chemical.smiles",
    "version": "0.1"
  },
  "data": {
    "smiles": "O=C1OC2=CC=CC=C2C=C1"
  }
}

OpenSmell Core verifies that the SMILES value is a non-empty string. It does not attempt to prove chemical validity. A chemical representation also does not imply that the represented molecule alone is sufficient to reproduce the perceived odor.


Experimental representation schemes

Experimental RFCs currently investigate richer representation schemes that are deliberately kept outside the normative OpenSmell 0.1 Core.

Semantic annotations

RFC-0004 investigates:

org.opensmell.semantic.annotations

The model distinguishes categorical states such as:

present
absent
unknown

This distinction is important for datasets where missing information must not automatically be interpreted as absence. The model has been tested using OdorNet data.

Quantitative perceptual measurements

RFC-0005 investigates:

org.opensmell.perceptual.measurements

The model represents quantitative perceptual measurements while preserving an important distinction:

measurement absent ≠ measured value 0

The model has been tested against the Keller/Vosshall DREAM Olfaction Prediction Challenge dataset. These schemes remain experimental and are not automatically part of OpenSmell 0.1 Core.


.osmell documents

OpenSmell 0.1 uses UTF-8 JSON. The recommended file extension is:

.osmell

Example:

{
  "opensmell": "0.1",
  "odor": {
    "id": "urn:uuid:550e8400-e29b-41d4-a716-446655440000",
    "metadata": {
      "labels": {
        "en": "Coumarin",
        "fr": "Coumarine"
      },
      "description": "Example odor with chemical and semantic representations."
    },
    "representations": [
      {
        "type": "chemical",
        "scheme": {
          "id": "org.opensmell.chemical.smiles",
          "version": "0.1"
        },
        "data": {
          "smiles": "O=C1OC2=CC=CC=C2C=C1"
        }
      },
      {
        "type": "semantic",
        "scheme": {
          "id": "org.opensmell.semantic.descriptors",
          "version": "0.1"
        },
        "data": {
          "descriptors": [
            {
              "value": "sweet",
              "language": "en"
            },
            {
              "value": "vanilla-like",
              "language": "en"
            }
          ]
        }
      }
    ]
  }
}

The same odor can therefore carry chemical and semantic information without requiring either representation to be derived from the other.


Extensibility and forward compatibility

OpenSmell is designed so that information unknown to one implementation can still be transported. Conceptually:

Known scheme + valid data
        │
        ▼
      ACCEPT
Known scheme + invalid data
        │
        ▼
      REJECT
Unknown scheme
        │
        ▼
      ACCEPT
        │
        ▼
Preserve opaque data

The Python implementation can preserve unknown extension fields at the following levels:

Document
├── extra
└── Odor
    ├── extra
    ├── Metadata
    │   └── extra
    └── Representation
        ├── extra
        └── Scheme
            └── extra

This allows newer or experimental information to survive a read/write cycle even when the implementation does not understand its meaning. Official OpenSmell fields always take precedence over extension fields. Applications that require preservation of document-level extension fields should use the complete Document API rather than discarding the root document structure.


Python reference implementation

OpenSmell currently provides a Python reference implementation. Supported versions:

Python 3.10+

Installation for development

Clone the repository:

git clone https://github.com/YAAASSS/OpenSmell.git
cd OpenSmell

Create a virtual environment:

python -m venv .venv

Activate it. Windows PowerShell:

.venv\Scripts\Activate.ps1

Linux/macOS:

source .venv/bin/activate

Install OpenSmell with development dependencies:

python -m pip install -e ".[dev]"

Loading an odor

The simple API returns the odor contained in an OpenSmell document:

import opensmell
odor = opensmell.load("examples/coffee.osmell")
print(odor.id)

Access metadata:

print(odor.metadata.labels["en"])

Access representations:

representation = odor.representations[0]
print(representation.type)
print(representation.scheme.id)
print(representation.scheme.version)

Lossless document loading

Applications such as editors, converters, proxies, or interoperability tools may need to preserve information they do not understand. For those applications, OpenSmell provides:

import opensmell
document = opensmell.load_document(
    "examples/coffee.osmell"
)
opensmell.dump(
    document,
    "coffee-copy.osmell"
)

load_document() returns the complete OpenSmell document model rather than only its odor. This allows document-level extension fields to survive the round trip. The original API remains available:

odor = opensmell.load("examples/coffee.osmell")

so existing code does not need to migrate to Document unless document-level preservation is required.


Creating OpenSmell objects

OpenSmell includes builders for common representations. Example:

from opensmell import builders
semantic = builders.semantic_descriptors(
    "coffee",
    "roasted",
    language="en",
)
chemical = builders.chemical_smiles(
    "CCO"
)
odor = builders.odor(
    representations=[
        semantic,
        chemical,
    ]
)

An identifier can be generated automatically for newly created odor objects. The resulting odor can be serialized:

import opensmell
opensmell.dump(
    odor,
    "example.osmell"
)

Validation

OpenSmell currently performs two levels of validation.

Core validation

The complete document is first required to belong to the strict JSON data domain and is then validated against the OpenSmell 0.1 JSON Schema.

The reference implementation rejects non-standard JSON numeric values such as NaN, Infinity, and -Infinity, including non-finite values produced while parsing numeric input. Serialization likewise rejects values that cannot be represented as strict JSON.

Schema validation then verifies structural requirements such as:

  • OpenSmell version;
  • odor identifier;
  • representations;
  • scheme identifiers and versions;
  • metadata structure;
  • required JSON types.

Scheme validation

If OpenSmell recognizes a representation scheme, its data is validated using the corresponding scheme validator. Conceptually:

.osmell
   │
   ▼
JSON Schema validation
   │
   ▼
Representation schemes
   │
   ├── known ──────► validate scheme data
   │
   └── unknown ────► preserve opaque data
   │
   ▼
Python objects

For registered schemes, OpenSmell also verifies that the representation type matches the type expected by the scheme. Unknown schemes are not rejected merely because the implementation does not recognize them. Experimental scheme validators may exist without being registered as normative OpenSmell 0.1 schemes.


Scheme Registry

The Python implementation contains a Scheme Registry. It maps:

scheme ID + version

to scheme-specific validation behavior. For example:

org.opensmell.semantic.descriptors
                 +
                0.1
                 │
                 ▼
           Scheme Registry
                 │
                 ▼
 semantic descriptor validator

This avoids hard-coding every future representation into the core parser.


OdorNet adapter

OpenSmell includes an experimental adapter for importing records from OdorNet. OdorNet provides molecular structures together with olfactory category labels. The adapter can convert an OdorNet record into OpenSmell representations. Conceptually:

OdorNet record
     │
     ├── SMILES
     │      │
     │      ▼
     │  chemical representation
     │
     └── odor annotations
            │
            ▼
       semantic representation
            │
            ▼
        OpenSmell Odor

The adapter does not make OdorNet part of the OpenSmell Core specification. OdorNet is an external source of olfactory information. The adapter is located at:

src/opensmell/adapters/odornet.py

OpenSmell experiments preserve the distinction between positive, negative, and unresolved OdorNet annotation states rather than assuming that missing information means absence.


Keller/Vosshall adapter

OpenSmell has also been tested against quantitative human olfactory measurements from the Keller/Vosshall DREAM Olfaction Prediction Challenge dataset. The experimental adapter is located at:

src/opensmell/adapters/keller_vosshall.py

This work motivated RFC-0005 and the distinction between:

semantic annotation
        ≠
quantitative perceptual measurement

It also preserves the distinction between:

measurement not performed
        ≠
measured value 0

The Keller/Vosshall dataset remains an external scientific dataset and is not part of the OpenSmell source distribution or Core specification.


Provenance experiment

Representation-level provenance is being investigated through RFC-0003. Example:

{
  "provenance": {
    "source": "OdorNet"
  }
}

This information can be preserved through the OpenSmell extension mechanism. Provenance is currently experimental. It is not yet a normative OpenSmell 0.1 Core field.


PubChem enrichment

OpenSmell contains an optional PubChem enrichment utility. It can resolve a SMILES structure to chemical identity information such as:

PubChem title
IUPAC name
canonical/connectivity SMILES
InChIKey

Conceptually:

SMILES
  │
  ▼
PubChem
  │
  ├── Title
  ├── IUPAC name
  ├── canonical/connectivity SMILES
  └── InChIKey

PubChem enrichment is intentionally separate from OpenSmell Core. OpenSmell does not require PubChem, network access, or any particular external chemical database to parse an .osmell document.


OdorNet dataset enrichment tool

The repository contains a development tool:

tools/enrich_odornet.py

It can enrich a local OdorNet dataset with PubChem chemical identity information. The tool supports:

  • persistent caching;
  • interruption and resume;
  • duplicate SMILES avoidance;
  • request throttling;
  • retries for temporary network/server failures;
  • periodic checkpoints;
  • enriched CSV generation. Generated datasets and PubChem caches are local development artifacts and are excluded from Git. The tool is not part of the OpenSmell Core protocol.

Experimental resource identification

RFC-0006 investigates a resource identification model for future OpenSmell resource graphs. The current experimental design distinguishes:

Scheme identifier
OpenSmell Resource ID
External/source identifier
Reference

These concepts serve different purposes and should not be conflated.

Resource IDs

The current experimental candidate uses canonical lowercase UUID strings. Two generation modes are investigated:

UUIDv4

for newly created resources without deterministic source identity, and:

UUIDv5

for deterministic imports of resources with stable source identity. RFC-0006 remains experimental and does not change the unrestricted non-empty-string odor.id rule of OpenSmell 0.1.

Deterministic source identity

Dataset imports can derive an experimental Resource ID from:

dataset
resource type
source identity

Source identity may be atomic:

"113L_038"

or composite:

{
  "stimulus": "1001_3.12e-13",
  "target": "111L_001"
}

Composite structural keys are deliberately restricted to:

^[a-z][a-z0-9_.-]\*$

while values may contain Unicode scalar strings. This restriction resulted from cross-language interoperability experiments showing that unconstrained Unicode object-key ordering can produce different canonical byte sequences in different runtimes. No implicit Unicode normalization is currently performed. Therefore canonically equivalent Unicode strings with different code-point sequences remain distinct source identities.


Identifier interoperability experiments

The experimental identifier implementation is located under:

src/opensmell/experimental/

The repository contains Python and JavaScript interoperability tooling. Golden and torture vectors test:

  • deterministic canonical serialization;
  • UTF-8 generation octets;
  • UUIDv5 generation;
  • quotes and backslashes;
  • JSON control-character escaping;
  • Unicode values;
  • CJK text;
  • emoji;
  • Unicode normalization differences;
  • composite identity ordering;
  • delimiter-boundary ambiguity;
  • invalid surrogate code points. The current torture-vector suite contains 17 vectors. Python and JavaScript reproduce identical canonical text, UTF-8 octets, and UUIDv5 values for all current vectors. These results are experimental evidence for RFC-0006, not a declaration that the identification model is final.

Burton 2022 identity experiment

OpenSmell also uses the Burton 2022 dataset distributed through Pyrfume as a real-world stress test for resource identity, graph structure, physiological Result data, and ResourceGraph serialization. This dataset contains physiological mouse olfactory-bulb response data. It is intentionally not treated as human perceptual measurement data. The experiment distinguishes:

Molecule
   │
   ▼
Stimulus
   │
   ▼
Observation ─────► ObservationTarget
   │
   ▼
Result

The deterministic identity experiment generated:

Molecules:          186
Stimuli:            227
Targets:          1,008
Observations:    187,748
------------------------
Total IDs:       189,169

with:

Unique generation names: 189,169
Unique Resource IDs:     189,169
Observed name collisions:      0
Observed UUID collisions:      0

The materialized experimental ResourceGraph deliberately does not invent a generic Chemical resource class for the 186 referenced molecule identities. Its dataset-scale JSON round-trip therefore contains:

Materialized resources:       188,983
Stimulus resources:               227
Observation targets:            1,008
Observations:                  187,748
Result objects:               187,748
Unresolved molecule IDs:          186
Source-less stimuli:                 1
Stimuli without conditions:          2
DeltaF values:                 187,748
Zero DeltaF:                   184,356
Non-zero DeltaF:                 3,392
Compact JSON bytes:         81,220,605

The complete graph survived:

ResourceGraph -> JSON -> ResourceGraph

with resource order, structural references, unresolved references, Result schemes, Result data, and DeltaF values preserved. A second serialization was also stable. The experiment preserves unresolved source references rather than inventing missing metadata or silently discarding them. The Burton dataset remains external to OpenSmell and is excluded from the source distribution.


Architecture

The current architecture can be summarized as:

External data / research
│
├── OdorNet
├── Keller/Vosshall
├── Burton / Pyrfume
├── UCI Gas Sensor Array Drift
├── OpenPOM
├── chemical databases
├── scientific datasets
└── future models
        │
        ▼
┌──────────────────────────────────────────┐
│                OpenSmell                 │
│                                          │
│  Core 0.1                                │
│  .osmell / JSON Schema                   │
│  models / parser / serializer            │
│  Scheme Registry / validation / builders │
│                                          │
│  Experimental interoperability           │
│  Resource identity                       │
│  Generic ResourceGraph                   │
│  Molecule / Annotation resources         │
│  Structural reference discovery          │
│  Dataset adapters / bridges              │
└──────────────────────────────────────────┘
        │
        ▼
  RenderRequest
        │
        ▼
SemanticChannelMapper
        │
        ▼
  RenderingPlan
        │
        ▼
DeviceCapabilities / DeviceAdapter
        │
        ▼
Device Protocol JSON 0.1
        │
        ▼
 DeviceTransport
        │
        ├── MemoryDeviceTransport
        └── SerialDeviceTransport
                    │
                    ▼
              physical device

The experimental resource architecture separates resource identity, graph transport, structural references, and scheme-defined interpretation. The rendering architecture separately converts selected graph information into a device-specific plan.

OpenSmell does not assume that a semantic descriptor, molecule, annotation, or other resource corresponds directly to a physical device channel. Mapping is explicitly device- or application-specific.

The rendering and device layers are experimental and are not part of OpenSmell 0.1 Core. Current serial work validates software interoperability and physical actuation paths; it does not demonstrate faithful odor reproduction.


Project structure

OpenSmell/
├── .github/workflows/tests.yml
├── examples/
│   ├── *.osmell
│   ├── geraniol.osmell
│   ├── generate_geraniol_osmell.py
│   ├── geraniol_esp32_render.py
│   ├── *_conformance_vectors.json
│   ├── *_interop_vectors.json
│   └── rendering / OdorNet demonstrations
├── rfcs/
│   ├── RFC-0001.md ... RFC-0008.md
│   ├── RFC-0009.md   # Molecule Resource Type
│   ├── RFC-0010.md   # Generic Annotation Resource
│   ├── RFC-0011.md   # Structural Reference Discovery
│   └── RFC-0012.md   # Rendering and Device Interoperability Architecture
├── schema/
│   ├── opensmell-0.1.schema.json
│   ├── experimental-resource-graph-0.1.schema.json
│   ├── experimental-generic-resource-graph-0.1.schema.json
│   ├── experimental-molecule-0.1.schema.json
│   └── experimental-annotation-0.1.schema.json
├── spec/opensmell-0.1.md
├── src/opensmell/
│   ├── adapters/
│   ├── enrichment/
│   ├── experimental/
│   │   ├── identifiers.py
│   │   ├── graph.py / graph_serialization.py
│   │   ├── generic_graph.py
│   │   ├── molecule.py / annotation.py
│   │   ├── reference_discovery.py
│   │   ├── odor_graph_bridge.py
│   │   ├── odornet_enriched_adapter.py
│   │   ├── rendering.py
│   │   ├── semantic_channel_mapper.py
│   │   ├── device_capabilities.py
│   │   ├── device_adapter.py
│   │   ├── render_pipeline.py
│   │   ├── device_protocol.py
│   │   ├── device_transport.py
│   │   ├── protocol_device_adapter.py
│   │   ├── serial_device_transport.py
│   │   └── simulated_diffuser.py
│   ├── schemas/
│   ├── schemes/
│   ├── builders.py
│   ├── models.py
│   ├── parser.py
│   ├── serializer.py
│   └── validation.py
├── hardware/
│   └── esp32/
│       ├── README.md
│       ├── esp32_physical_render.py
│       └── opensmell_device_protocol_0_1/
│           └── opensmell_device_protocol_0_1.ino
├── tests/
├── tools/
├── LICENSE
├── pyproject.toml
└── README.md

Some experimental tools and adapters operate on external scientific datasets. Those datasets are not part of the OpenSmell source distribution and are excluded from Git where required.


Running tests

Install development dependencies and run:

python -m pip install -e ".[dev]"
python -m pytest

Serial support is optional for normal OpenSmell users:

python -m pip install -e ".[serial]"

The latest audited local run passes more than 1,700 automated Python tests. Exact counts are not treated as a stable project property because the suite grows as experimental interoperability work is added.

The audited suite includes the Geraniol software rendering-pipeline regression test. Physical ESP32 validation is intentionally manual and is not part of the normal automated test suite.

The suite covers Core and experimental behavior, including parsing, serialization, builders, JSON Schema consistency, known and unknown schemes, extension preservation, lossless document round trips, dataset adapters, deterministic resource identity, ResourceGraph serialization, portable conformance vectors, Python/JavaScript interoperability, Molecule and Annotation resources, structural reference discovery, rendering, device capabilities, device adapters, the experimental JSON device protocol, transport boundaries, and serial protocol integration.

GitHub Actions runs the Python suite against Python 3.10, 3.11, 3.12, and 3.13. Cross-language interoperability checks use Node.js where applicable.

Some dataset-scale experiments are development tools rather than normal unit tests because the underlying external datasets are not distributed with OpenSmell.

Three complete experimental RFC-0007 ResourceGraph JSON round trips have succeeded:

UCI Gas Sensor Array Drift
  resources:          14,144
  JSON bytes:     61,600,816
Keller/Vosshall
  resources:          56,015
  JSON bytes:     47,993,421
Burton 2022
  resources:         188,983
  JSON bytes:     81,220,605

Combined:

Materialized resources: 259,142
Compact JSON bytes:     190,814,842

These experiments cover electronic olfaction, human psychophysics, and biological physiology. Additional RFC-0008 experiments validate extensible resource types, unknown-resource preservation, Molecule and Annotation resources, and structural reference discovery.


Physical ESP32 prototype

OpenSmell now includes an experimental physical endpoint validation using an ESP32 and an LED as an observable stand-in actuator.

The generic hardware validation can be run with:

python hardware\esp32\esp32_physical_render.py --port COM8

Replace COM8 with the serial port assigned to the ESP32.

The firmware is located at:

hardware/esp32/opensmell_device_protocol_0_1/
    opensmell_device_protocol_0_1.ino

The tested prototype exposes Device Protocol 0.1 over newline-delimited UTF-8 JSON at 115200 baud. It advertises device ID opensmell-esp32-led-001, channel 0, normalized intensity 0.0 through 1.0, and rendering durations from 0.1 through 30.0 seconds.

A valid render request is acknowledged without blocking for the complete rendering duration, after which timed actuator execution continues independently. The physical device validates channel, intensity, and duration independently of client-side checks.

The current ESP32 firmware also bounds each newline-delimited serial message to 1024 bytes. Oversized frames are discarded through their terminating newline and rejected with message_too_large, allowing the following frame to be processed normally. This limit is specific to the experimental ESP32 prototype and is not a universal Device Protocol 0.1 limit.

Oversized-frame rejection and subsequent frame resynchronization have been validated on the physical ESP32.

A longer demonstration uses the committed Geraniol example:

python examples\geraniol_esp32_render.py --port COM8

The demonstrated path is:

geraniol.osmell
    -> Core OpenSmell Odor
    -> ResourceGraph
    -> SemanticChannelMapper
    -> RenderingPlan
    -> Device Protocol 0.1
    -> SerialDeviceTransport
    -> ESP32
    -> LED

For this demonstration only, application policy maps:

floral -> channel 0

This mapping is not a universal OpenSmell channel meaning. The LED validates the software-to-hardware control path; it does not reproduce Geraniol or any other physical odor.

See hardware/esp32/README.md and RFC-0012 for the prototype boundaries, validation evidence, and remaining open questions.


Relationship with existing work

OpenSmell does not assume that digital olfaction begins with this project. Existing research, standards, datasets, models, and olfactory interfaces already address important parts of the problem. Relevant work includes:

MPEG-V / ISO/IEC 23005

MPEG-V defines representations and control mechanisms for sensory effects, including olfactory effects. OpenSmell should investigate interoperability with MPEG-V rather than duplicate existing standardization work.

OWidgets

OWidgets explored device-independent olfactory experience design and communication with scent-delivery devices. Its work on mapping, scheduling, and uniform device interfaces is relevant prior art for OpenSmell.

OpenPOM

OpenPOM provides open-source machine-learning tools related to perceptual odor mapping. Future OpenSmell representations could potentially transport outputs from models of this kind.

OdorNet

OdorNet provides molecular olfactory labels and datasets. OpenSmell currently includes an experimental adapter for converting OdorNet records into OpenSmell representations. OdorNet remains an external data source rather than part of the OpenSmell specification.

Keller/Vosshall

The Keller/Vosshall DREAM Olfaction Prediction Challenge dataset contains quantitative human olfactory measurements. OpenSmell uses this dataset experimentally to test the distinction between categorical semantic information and quantitative perceptual measurements. The dataset remains external to OpenSmell.

Pyrfume / Burton 2022

Pyrfume provides structured olfactory datasets. The Burton 2022 archive is used experimentally to investigate molecules, stimuli, biological observations, source identifiers, and deterministic resource identity. The physiological DeltaF responses in this dataset are not treated as human perceptual measurements.

D2Smell

D2Smell is ongoing research into the digitization and remote reproduction of smell. Future results from projects such as D2Smell may help define useful perceptual or renderable representations.

Scentree

Scentree is an open-source olfactory display project and represents the type of hardware that could eventually be explored through an OpenSmell device adapter. OpenSmell's objective is therefore interoperability, not claiming invention of digital smell transmission.


RFCs

Significant architectural decisions are documented and explored through RFCs. Current RFCs:

RFC-0001  OpenSmell Vision and Scope
RFC-0002  Odor Representation Model
RFC-0003  Representation Provenance
RFC-0004  Semantic Annotation Model
RFC-0005  Quantitative Perceptual Measurement Model
RFC-0006  Resource Identification and Deterministic Source Identity
RFC-0007  Stimulus and Observation Resource Model
RFC-0008  Generic Resource Graph and Extensible Resource Types
RFC-0009  Molecule Resource Type
RFC-0010  Generic Annotation Resource
RFC-0011  Structural Reference Discovery and Graph Navigation
RFC-0012  Experimental Rendering and Device Interoperability Architecture

RFCs allow experimental concepts to be investigated without prematurely making them part of the OpenSmell Core specification.

RFC-0003 investigates provenance without making provenance a normative Core 0.1 field. RFC-0004 preserves present, absent, and unknown semantic annotation states. RFC-0005 investigates quantitative perceptual measurements. RFC-0006 investigates deterministic resource identity and cross-language generation. RFC-0007 introduced Stimulus/Observation resources and the first experimental ResourceGraph. RFC-0008 generalizes that graph so unknown future resource types can be preserved. RFC-0009 adds an experimental Molecule resource. RFC-0010 adds a generic Annotation resource. RFC-0011 adds registered structural reference discovery and graph navigation without scanning arbitrary opaque JSON. RFC-0012 documents the experimental rendering, device, protocol, and transport architecture and records the first physical ESP32/LED validation without making those layers part of Core 0.1.

All of these RFCs remain experimental Draft work unless explicitly incorporated into a future OpenSmell specification. Experimental RFCs do not automatically modify OpenSmell 0.1 Core.


Roadmap

OpenSmell 0.1 foundation

Completed:

  • .osmell JSON representation and Core JSON Schema
  • Python data models, parser, serializer, builders, and validation
  • representation Scheme Registry and built-in schemes
  • unknown scheme support and extension preservation
  • lossless Document model
  • OpenSmell 0.1 specification
  • Python packaging and multi-version CI
  • RFC process
  • OdorNet, Keller/Vosshall, and PubChem experiments

Interoperability research completed or in progress

  • semantic annotation model and OdorNet annotation round trip
  • quantitative perceptual measurement model and Keller/Vosshall round trip
  • deterministic resource identity and Python/JavaScript identifier tests
  • RFC-0007 Stimulus/Observation ResourceGraph experiments
  • dataset-scale UCI, Keller/Vosshall, and Burton graph round trips
  • RFC-0007 structural schema and portable conformance vectors
  • Python/JavaScript ResourceGraph interoperability
  • RFC-0008 Generic ResourceGraph and ResourceTypeRegistry
  • unknown future resource preservation
  • RFC-0008 generic graph schema and portable conformance vectors
  • RFC-0009 Molecule resource, schema, conformance, and real-data validation
  • RFC-0010 Annotation resource, schema, conformance, and real-data validation
  • RFC-0011 structural reference discovery and cross-language vectors
  • Core Odor to ResourceGraph bridge experiment
  • enriched OdorNet ResourceGraph adapter
  • rendering request / plan model
  • semantic channel mapper
  • device capability and adapter boundaries
  • simulated and multi-device rendering experiments
  • experimental JSON device protocol 0.1
  • protocol-backed device adapter
  • transport abstraction and in-memory transport
  • optional serial transport using PySerial
  • serial protocol integration without physical hardware
  • physical ESP32/LED validation of the serial/device control path
  • Geraniol .osmell to ResourceGraph to mapper to ESP32/LED demonstration

Next investigations

  • validate the current serial/device path on physical ESP32 hardware
  • document rendering and device interoperability through RFC-0012
  • create portable Device Protocol 0.1 conformance artifacts
  • extend CI across the existing independent JavaScript verifiers
  • investigate provenance integration with resource graphs
  • define resource type namespace/version governance
  • investigate streaming or partial loading for large ResourceGraphs
  • investigate normative serialization and canonicalization requirements
  • investigate mixture and renderable representations
  • investigate MPEG-V interoperability
  • add CLI tooling
  • publish project documentation through opensmell.org
  • define the OpenSmell 0.2 roadmap

The roadmap is intentionally incremental. New concepts should demonstrate a real interoperability need through experiments and real data before being incorporated into OpenSmell Core.


What OpenSmell is not

OpenSmell is currently not:

  • a physical smell generator;
  • an electronic nose;
  • a chemical analysis platform;
  • an odor prediction model;
  • a finished networking protocol;
  • a replacement for MPEG-V;
  • a standardized set of universal odor primaries;
  • a universal database of odor molecules;
  • a claim that arbitrary smells can currently be perfectly digitized and reproduced. OpenSmell is an experimental interoperability framework intended to connect technologies that address parts of those problems.

Current status

OpenSmell is currently in pre-alpha experimental development.

The first public development release is:

v0.1.0

Development on main has progressed substantially beyond that release. The current repository contains experimental work through RFC-0012, including the Generic ResourceGraph, Molecule and Annotation resources, structural reference discovery, dataset bridges, rendering plans, device capabilities, device adapters, an experimental JSON device protocol, transport-independent protocol adapters, and optional serial transport.

The latest audited local run passes more than 1,700 automated Python tests. Portable conformance and independent Python/JavaScript checks exercise several experimental interoperability contracts, including Device Protocol 0.1.

Dataset-scale ResourceGraph experiments span human psychophysics, biological physiology, and electronic olfaction.

The format and APIs may still change before a stable 1.0 specification. Do not rely on the current experimental graph, rendering, device, or protocol APIs for production systems.

The first physical device-boundary milestone has now been completed with an ESP32 and LED stand-in actuator. The experiment validated serial communication, device discovery and capabilities, plan delivery, device-side validation, and timed physical output. A Geraniol example also exercised the longer path from an .osmell document through ResourceGraph, semantic mapping, Device Protocol 0.1, serial transport, and the ESP32.

The demonstration used the application-level policy floral -> channel 0. This is not a universal channel meaning and does not constitute physical odor reproduction.

The rendering/device architecture and the physical validation evidence are documented by RFC-0012. Experimental concepts will only be considered for a future OpenSmell Core after sufficient independent evidence.


Project namespace

The project controls:

opensmell.org

The OpenSmell 0.1 JSON Schema therefore uses the identifier:

https://opensmell.org/schema/opensmell-0.1.schema.json

The domain is intended to provide a stable namespace for future specifications, schemas, RFCs, and documentation. The project website and documentation infrastructure are not yet deployed.


Contributing

OpenSmell is being developed openly. Contributions, technical discussions, prior-art references, experiments, and criticism of the architecture are welcome. Areas of particular interest include:

  • digital olfaction research;
  • olfactory perception;
  • odor representation;
  • machine learning for olfaction;
  • scent display hardware;
  • interoperability;
  • sensory standards;
  • VR/AR olfactory interfaces;
  • serialization and protocol design. Because OpenSmell is experimental, proposals should preferably be supported by concrete interoperability requirements, existing research, real datasets, or reproducible experiments.

License

OpenSmell is licensed under the Apache License 2.0. See the LICENSE file for details. External scientific datasets used for experiments retain their respective licenses and are not automatically covered by the OpenSmell license.


Project

OpenSmell is developed as an independent open-source experiment into interoperability for digital olfaction. Repository:

YAAASSS/OpenSmell

Project namespace:

opensmell.org

OpenSmell — an open interoperability layer for digital olfaction.

About

OpenSmell is an open interoperability framework for representing, exchanging, and rendering digital olfactory information across applications and devices.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages